]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/librgw.cc
update sources to v12.2.5
[ceph.git] / ceph / src / rgw / librgw.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
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
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 */
31f18b77 14#include "include/compat.h"
7c673cae
FG
15#include <sys/types.h>
16#include <string.h>
17#include <chrono>
18
19#include "include/types.h"
20#include "include/rados/librgw.h"
21#include "rgw/rgw_acl_s3.h"
22#include "rgw_acl.h"
23
24#include "include/str_list.h"
224ce89b 25#include "include/stringify.h"
7c673cae 26#include "global/global_init.h"
b32b8144 27#include "global/signal_handler.h"
7c673cae
FG
28#include "common/config.h"
29#include "common/errno.h"
30#include "common/Timer.h"
31#include "common/Throttle.h"
32#include "common/WorkQueue.h"
33#include "common/ceph_argparse.h"
34#include "common/ceph_context.h"
35#include "common/common_init.h"
36#include "common/dout.h"
37
38#include "rgw_rados.h"
39#include "rgw_resolve.h"
40#include "rgw_op.h"
41#include "rgw_rest.h"
42#include "rgw_frontend.h"
43#include "rgw_request.h"
44#include "rgw_process.h"
45#include "rgw_rest_user.h"
46#include "rgw_rest_s3.h"
47#include "rgw_os_lib.h"
48#include "rgw_auth.h"
49#include "rgw_auth_s3.h"
50#include "rgw_lib.h"
51#include "rgw_lib_frontend.h"
52
53#include <errno.h>
54#include <chrono>
55#include <thread>
56#include <string>
57#include <string.h>
58#include <mutex>
59
60
61#define dout_subsys ceph_subsys_rgw
62
63bool global_stop = false;
64
b32b8144
FG
65static void handle_sigterm(int signum)
66{
67 dout(20) << __func__ << " SIGUSR1 ignored" << dendl;
68}
69
7c673cae
FG
70namespace rgw {
71
72 using std::string;
73
74 static std::mutex librgw_mtx;
75
76 RGWLib rgwlib;
77
78 class C_InitTimeout : public Context {
79 public:
80 C_InitTimeout() {}
81 void finish(int r) override {
82 derr << "Initialization timeout, failed to initialize" << dendl;
83 exit(1);
84 }
85 };
86
87 void RGWLibProcess::checkpoint()
88 {
89 m_tp.drain(&req_wq);
90 }
91
92#define MIN_EXPIRE_S 120
93
94 void RGWLibProcess::run()
95 {
96 /* write completion interval */
97 RGWLibFS::write_completion_interval_s =
98 cct->_conf->rgw_nfs_write_completion_interval_s;
99
100 /* start write timer */
101 RGWLibFS::write_timer.resume();
102
103 /* gc loop */
104 while (! shutdown) {
105 lsubdout(cct, rgw, 5) << "RGWLibProcess GC" << dendl;
106
107 /* dirent invalidate timeout--basically, the upper-bound on
108 * inconsistency with the S3 namespace */
109 auto expire_s = cct->_conf->rgw_nfs_namespace_expire_secs;
110
111 /* delay between gc cycles */
c07f9fc5 112 auto delay_s = std::max(int64_t(1), std::min(int64_t(MIN_EXPIRE_S), expire_s/2));
7c673cae
FG
113
114 unique_lock uniq(mtx);
115 restart:
116 int cur_gen = gen;
117 for (auto iter = mounted_fs.begin(); iter != mounted_fs.end();
118 ++iter) {
119 RGWLibFS* fs = iter->first->ref();
120 uniq.unlock();
121 fs->gc();
122 fs->rele();
123 uniq.lock();
124 if (cur_gen != gen)
125 goto restart; /* invalidated */
126 }
127 uniq.unlock();
128 std::this_thread::sleep_for(std::chrono::seconds(delay_s));
129 }
130 }
131
132 void RGWLibProcess::handle_request(RGWRequest* r)
133 {
134 /*
135 * invariant: valid requests are derived from RGWLibRequst
136 */
137 RGWLibRequest* req = static_cast<RGWLibRequest*>(r);
138
139 // XXX move RGWLibIO and timing setup into process_request
140
141#if 0 /* XXX */
142 utime_t tm = ceph_clock_now();
143#endif
144
145 RGWLibIO io_ctx;
146
147 int ret = process_request(req, &io_ctx);
148 if (ret < 0) {
149 /* we don't really care about return code */
150 dout(20) << "process_request() returned " << ret << dendl;
151
152 }
153 delete req;
154 } /* handle_request */
155
156 int RGWLibProcess::process_request(RGWLibRequest* req)
157 {
158 // XXX move RGWLibIO and timing setup into process_request
159
160#if 0 /* XXX */
161 utime_t tm = ceph_clock_now();
162#endif
163
164 RGWLibIO io_ctx;
165
166 int ret = process_request(req, &io_ctx);
167 if (ret < 0) {
168 /* we don't really care about return code */
169 dout(20) << "process_request() returned " << ret << dendl;
170 }
171 return ret;
172 } /* process_request */
173
174 static inline void abort_req(struct req_state *s, RGWOp *op, int err_no)
175 {
176 if (!s)
177 return;
178
179 /* XXX the dump_errno and dump_bucket_from_state behaviors in
180 * the abort_early (rgw_rest.cc) might be valuable, but aren't
181 * safe to call presently as they return HTTP data */
182
183 perfcounter->inc(l_rgw_failed_req);
184 } /* abort_req */
185
186 int RGWLibProcess::process_request(RGWLibRequest* req, RGWLibIO* io)
187 {
188 int ret = 0;
189 bool should_log = true; // XXX
190
191 dout(1) << "====== " << __func__
192 << " starting new request req=" << hex << req << dec
193 << " ======" << dendl;
194
195 /*
196 * invariant: valid requests are derived from RGWOp--well-formed
197 * requests should have assigned RGWRequest::op in their descendant
198 * constructor--if not, the compiler can find it, at the cost of
199 * a runtime check
200 */
201 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
202 if (! op) {
203 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
204 return -EINVAL;
205 }
206
207 io->init(req->cct);
208
209 perfcounter->inc(l_rgw_req);
210
211 RGWEnv& rgw_env = io->get_env();
212
213 /* XXX
214 * until major refactoring of req_state and req_info, we need
215 * to build their RGWEnv boilerplate from the RGWLibRequest,
216 * pre-staging any strings (HTTP_HOST) that provoke a crash when
217 * not found
218 */
219
220 /* XXX for now, use ""; could be a legit hostname, or, in future,
221 * perhaps a tenant (Yehuda) */
222 rgw_env.set("HTTP_HOST", "");
223
224 /* XXX and -then- bloat up req_state with string copies from it */
225 struct req_state rstate(req->cct, &rgw_env, req->get_user());
226 struct req_state *s = &rstate;
227
228 // XXX fix this
229 s->cio = io;
230
231 RGWObjectCtx rados_ctx(store, s); // XXX holds std::map
232
233 /* XXX and -then- stash req_state pointers everywhere they are needed */
234 ret = req->init(rgw_env, &rados_ctx, io, s);
235 if (ret < 0) {
236 dout(10) << "failed to initialize request" << dendl;
237 abort_req(s, op, ret);
238 goto done;
239 }
240
241 /* req is-a RGWOp, currently initialized separately */
242 ret = req->op_init();
243 if (ret < 0) {
244 dout(10) << "failed to initialize RGWOp" << dendl;
245 abort_req(s, op, ret);
246 goto done;
247 }
248
94b18763
FG
249 /* now expected by rgw_log_op() */
250 rgw_env.set("REQUEST_METHOD", s->info.method);
251 rgw_env.set("REQUEST_URI", s->info.request_uri);
252 rgw_env.set("QUERY_STRING", "");
253
7c673cae
FG
254 /* XXX authorize does less here then in the REST path, e.g.,
255 * the user's info is cached, but still incomplete */
256 req->log(s, "authorizing");
257 ret = req->authorize();
258 if (ret < 0) {
259 dout(10) << "failed to authorize request" << dendl;
260 abort_req(s, op, ret);
261 goto done;
262 }
263
264 /* FIXME: remove this after switching all handlers to the new authentication
265 * infrastructure. */
266 if (! s->auth.identity) {
267 s->auth.identity = rgw::auth::transform_old_authinfo(s);
268 }
269
270 req->log(s, "reading op permissions");
271 ret = req->read_permissions(op);
272 if (ret < 0) {
273 abort_req(s, op, ret);
274 goto done;
275 }
276
277 req->log(s, "init op");
278 ret = op->init_processing();
279 if (ret < 0) {
280 abort_req(s, op, ret);
281 goto done;
282 }
283
284 req->log(s, "verifying op mask");
285 ret = op->verify_op_mask();
286 if (ret < 0) {
287 abort_req(s, op, ret);
288 goto done;
289 }
290
291 req->log(s, "verifying op permissions");
292 ret = op->verify_permission();
293 if (ret < 0) {
294 if (s->system_request) {
295 dout(2) << "overriding permissions due to system operation" << dendl;
296 } else if (s->auth.identity->is_admin_of(s->user->user_id)) {
297 dout(2) << "overriding permissions due to admin operation" << dendl;
298 } else {
299 abort_req(s, op, ret);
300 goto done;
301 }
302 }
303
304 req->log(s, "verifying op params");
305 ret = op->verify_params();
306 if (ret < 0) {
307 abort_req(s, op, ret);
308 goto done;
309 }
310
311 req->log(s, "executing");
312 op->pre_exec();
313 op->execute();
314 op->complete();
315
316 done:
317 try {
318 io->complete_request();
319 } catch (rgw::io::Exception& e) {
320 dout(0) << "ERROR: io->complete_request() returned "
321 << e.what() << dendl;
322 }
323 if (should_log) {
324 rgw_log_op(store, nullptr /* !rest */, s,
325 (op ? op->name() : "unknown"), olog);
326 }
327
328 int http_ret = s->err.http_ret;
329
330 req->log_format(s, "http status=%d", http_ret);
331
332 dout(1) << "====== " << __func__
333 << " req done req=" << hex << req << dec << " http_status="
334 << http_ret
335 << " ======" << dendl;
336
337 return (ret < 0 ? ret : s->err.ret);
338 } /* process_request */
339
340 int RGWLibProcess::start_request(RGWLibContinuedReq* req)
341 {
342
343 dout(1) << "====== " << __func__
344 << " starting new continued request req=" << hex << req << dec
345 << " ======" << dendl;
346
347 /*
348 * invariant: valid requests are derived from RGWOp--well-formed
349 * requests should have assigned RGWRequest::op in their descendant
350 * constructor--if not, the compiler can find it, at the cost of
351 * a runtime check
352 */
353 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
354 if (! op) {
355 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
356 return -EINVAL;
357 }
358
359 struct req_state* s = req->get_state();
360
361 /* req is-a RGWOp, currently initialized separately */
362 int ret = req->op_init();
363 if (ret < 0) {
364 dout(10) << "failed to initialize RGWOp" << dendl;
365 abort_req(s, op, ret);
366 goto done;
367 }
368
369 /* XXX authorize does less here then in the REST path, e.g.,
370 * the user's info is cached, but still incomplete */
371 req->log(s, "authorizing");
372 ret = req->authorize();
373 if (ret < 0) {
374 dout(10) << "failed to authorize request" << dendl;
375 abort_req(s, op, ret);
376 goto done;
377 }
378
379 /* FIXME: remove this after switching all handlers to the new authentication
380 * infrastructure. */
381 if (! s->auth.identity) {
382 s->auth.identity = rgw::auth::transform_old_authinfo(s);
383 }
384
385 req->log(s, "reading op permissions");
386 ret = req->read_permissions(op);
387 if (ret < 0) {
388 abort_req(s, op, ret);
389 goto done;
390 }
391
392 req->log(s, "init op");
393 ret = op->init_processing();
394 if (ret < 0) {
395 abort_req(s, op, ret);
396 goto done;
397 }
398
399 req->log(s, "verifying op mask");
400 ret = op->verify_op_mask();
401 if (ret < 0) {
402 abort_req(s, op, ret);
403 goto done;
404 }
405
406 req->log(s, "verifying op permissions");
407 ret = op->verify_permission();
408 if (ret < 0) {
409 if (s->system_request) {
410 dout(2) << "overriding permissions due to system operation" << dendl;
411 } else if (s->auth.identity->is_admin_of(s->user->user_id)) {
412 dout(2) << "overriding permissions due to admin operation" << dendl;
413 } else {
414 abort_req(s, op, ret);
415 goto done;
416 }
417 }
418
419 req->log(s, "verifying op params");
420 ret = op->verify_params();
421 if (ret < 0) {
422 abort_req(s, op, ret);
423 goto done;
424 }
425
426 op->pre_exec();
427 req->exec_start();
428
429 done:
430 return (ret < 0 ? ret : s->err.ret);
431 }
432
433 int RGWLibProcess::finish_request(RGWLibContinuedReq* req)
434 {
435 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
436 if (! op) {
437 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
438 return -EINVAL;
439 }
440
441 int ret = req->exec_finish();
442 int op_ret = op->get_ret();
443
444 dout(1) << "====== " << __func__
445 << " finishing continued request req=" << hex << req << dec
446 << " op status=" << op_ret
447 << " ======" << dendl;
448
449 return ret;
450 }
451
452 int RGWLibFrontend::init()
453 {
454 pprocess = new RGWLibProcess(g_ceph_context, &env,
455 g_conf->rgw_thread_pool_size, conf);
456 return 0;
457 }
458
459 int RGWLib::init()
460 {
461 vector<const char*> args;
462 return init(args);
463 }
464
465 int RGWLib::init(vector<const char*>& args)
466 {
467 int r = 0;
468
469 /* alternative default for module */
470 vector<const char *> def_args;
471 def_args.push_back("--debug-rgw=1/5");
472 def_args.push_back("--keyring=$rgw_data/keyring");
473 def_args.push_back("--log-file=/var/log/radosgw/$cluster-$name.log");
474
475 cct = global_init(&def_args, args,
476 CEPH_ENTITY_TYPE_CLIENT,
477 CODE_ENVIRONMENT_DAEMON,
478 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS);
479
480 Mutex mutex("main");
481 SafeTimer init_timer(g_ceph_context, mutex);
482 init_timer.init();
483 mutex.Lock();
484 init_timer.add_event_after(g_conf->rgw_init_timeout, new C_InitTimeout);
485 mutex.Unlock();
486
487 common_init_finish(g_ceph_context);
488
489 rgw_tools_init(g_ceph_context);
490
491 rgw_init_resolver();
492
493 store = RGWStoreManager::get_storage(g_ceph_context,
494 g_conf->rgw_enable_gc_threads,
495 g_conf->rgw_enable_lc_threads,
496 g_conf->rgw_enable_quota_threads,
31f18b77
FG
497 g_conf->rgw_run_sync_thread,
498 g_conf->rgw_dynamic_resharding);
7c673cae
FG
499
500 if (!store) {
501 mutex.Lock();
502 init_timer.cancel_all_events();
503 init_timer.shutdown();
504 mutex.Unlock();
505
506 derr << "Couldn't init storage provider (RADOS)" << dendl;
507 return -EIO;
508 }
509
510 r = rgw_perf_start(g_ceph_context);
511
512 rgw_rest_init(g_ceph_context, store, store->get_zonegroup());
513
514 mutex.Lock();
515 init_timer.cancel_all_events();
516 init_timer.shutdown();
517 mutex.Unlock();
518
519 if (r)
520 return -EIO;
521
522 const string& ldap_uri = store->ctx()->_conf->rgw_ldap_uri;
523 const string& ldap_binddn = store->ctx()->_conf->rgw_ldap_binddn;
524 const string& ldap_searchdn = store->ctx()->_conf->rgw_ldap_searchdn;
525 const string& ldap_searchfilter = store->ctx()->_conf->rgw_ldap_searchfilter;
526 const string& ldap_dnattr =
527 store->ctx()->_conf->rgw_ldap_dnattr;
528 std::string ldap_bindpw = parse_rgw_ldap_bindpw(store->ctx());
529
530 ldh = new rgw::LDAPHelper(ldap_uri, ldap_binddn, ldap_bindpw.c_str(),
531 ldap_searchdn, ldap_searchfilter, ldap_dnattr);
532 ldh->init();
533 ldh->bind();
534
535 rgw_user_init(store);
536 rgw_bucket_init(store->meta_mgr);
537 rgw_log_usage_init(g_ceph_context, store);
538
539 // XXX ex-RGWRESTMgr_lib, mgr->set_logging(true)
540
541 if (!g_conf->rgw_ops_log_socket_path.empty()) {
542 olog = new OpsLogSocket(g_ceph_context, g_conf->rgw_ops_log_data_backlog);
543 olog->init(g_conf->rgw_ops_log_socket_path);
544 }
545
546 int port = 80;
547 RGWProcessEnv env = { store, &rest, olog, port };
548
224ce89b 549 string fe_count{"0"};
7c673cae
FG
550 fec = new RGWFrontendConfig("rgwlib");
551 fe = new RGWLibFrontend(env, fec);
552
b32b8144
FG
553 init_async_signal_handler();
554 register_async_signal_handler(SIGUSR1, handle_sigterm);
555
224ce89b
WB
556 map<string, string> service_map_meta;
557 service_map_meta["pid"] = stringify(getpid());
558 service_map_meta["frontend_type#" + fe_count] = "rgw-nfs";
559 service_map_meta["frontend_config#" + fe_count] = fec->get_config();
560
7c673cae
FG
561 fe->init();
562 if (r < 0) {
563 derr << "ERROR: failed initializing frontend" << dendl;
564 return r;
565 }
566
567 fe->run();
568
224ce89b
WB
569 r = store->register_to_service_map("rgw-nfs", service_map_meta);
570 if (r < 0) {
571 derr << "ERROR: failed to register to service map: " << cpp_strerror(-r) << dendl;
572 /* ignore error */
573 }
574
7c673cae
FG
575 return 0;
576 } /* RGWLib::init() */
577
578 int RGWLib::stop()
579 {
580 derr << "shutting down" << dendl;
581
582 fe->stop();
583
584 fe->join();
585
586 delete fe;
587 delete fec;
588 delete ldh;
589
b32b8144
FG
590 unregister_async_signal_handler(SIGUSR1, handle_sigterm);
591 shutdown_async_signal_handler();
592
7c673cae
FG
593 rgw_log_usage_finalize();
594
595 delete olog;
596
597 RGWStoreManager::close_storage(store);
598
599 rgw_tools_cleanup();
600 rgw_shutdown_resolver();
601
602 rgw_perf_stop(g_ceph_context);
603
604 dout(1) << "final shutdown" << dendl;
605 cct.reset();
606
607 return 0;
608 } /* RGWLib::stop() */
609
610 int RGWLibIO::set_uid(RGWRados *store, const rgw_user& uid)
611 {
612 int ret = rgw_get_user_info_by_uid(store, uid, user_info, NULL);
613 if (ret < 0) {
614 derr << "ERROR: failed reading user info: uid=" << uid << " ret="
615 << ret << dendl;
616 }
617 return ret;
618 }
619
620 int RGWLibRequest::read_permissions(RGWOp* op) {
621 /* bucket and object ops */
622 int ret =
623 rgw_build_bucket_policies(rgwlib.get_store(), get_state());
624 if (ret < 0) {
625 ldout(get_state()->cct, 10) << "read_permissions (bucket policy) on "
626 << get_state()->bucket << ":"
627 << get_state()->object
628 << " only_bucket=" << only_bucket()
629 << " ret=" << ret << dendl;
630 if (ret == -ENODATA)
631 ret = -EACCES;
632 } else if (! only_bucket()) {
633 /* object ops */
634 ret = rgw_build_object_policies(rgwlib.get_store(), get_state(),
635 op->prefetch_data());
636 if (ret < 0) {
637 ldout(get_state()->cct, 10) << "read_permissions (object policy) on"
638 << get_state()->bucket << ":"
639 << get_state()->object
640 << " ret=" << ret << dendl;
641 if (ret == -ENODATA)
642 ret = -EACCES;
643 }
644 }
645 return ret;
646 } /* RGWLibRequest::read_permissions */
647
648 int RGWHandler_Lib::authorize()
649 {
650 /* TODO: handle
651 * 1. subusers
652 * 2. anonymous access
653 * 3. system access
654 * 4. ?
655 *
656 * Much or all of this depends on handling the cached authorization
657 * correctly (e.g., dealing with keystone) at mount time.
658 */
659 s->perm_mask = RGW_PERM_FULL_CONTROL;
660
661 // populate the owner info
662 s->owner.set_id(s->user->user_id);
663 s->owner.set_name(s->user->display_name);
664
665 return 0;
666 } /* RGWHandler_Lib::authorize */
667
668} /* namespace rgw */
669
670extern "C" {
671
672int librgw_create(librgw_t* rgw, int argc, char **argv)
673{
674 using namespace rgw;
675
676 int rc = -EINVAL;
677
678 if (! g_ceph_context) {
679 std::lock_guard<std::mutex> lg(librgw_mtx);
680 if (! g_ceph_context) {
681 vector<const char*> args;
682 std::vector<std::string> spl_args;
683 // last non-0 argument will be split and consumed
684 if (argc > 1) {
685 const std::string spl_arg{argv[(--argc)]};
686 get_str_vec(spl_arg, " \t", spl_args);
687 }
688 argv_to_vec(argc, const_cast<const char**>(argv), args);
689 // append split args, if any
690 for (const auto& elt : spl_args) {
691 args.push_back(elt.c_str());
692 }
693 env_to_vec(args);
694 rc = rgwlib.init(args);
695 }
696 }
697
698 *rgw = g_ceph_context->get();
699
700 return rc;
701}
702
703void librgw_shutdown(librgw_t rgw)
704{
705 using namespace rgw;
706
707 CephContext* cct = static_cast<CephContext*>(rgw);
708 rgwlib.stop();
709 cct->put();
710}
711
712} /* extern "C" */