1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
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.
14 #include "include/compat.h"
15 #include <sys/types.h>
19 #include "include/types.h"
20 #include "include/rados/librgw.h"
21 #include "rgw/rgw_acl_s3.h"
24 #include "include/str_list.h"
25 #include "include/stringify.h"
26 #include "global/global_init.h"
27 #include "common/config.h"
28 #include "common/errno.h"
29 #include "common/Timer.h"
30 #include "common/Throttle.h"
31 #include "common/WorkQueue.h"
32 #include "common/ceph_argparse.h"
33 #include "common/ceph_context.h"
34 #include "common/common_init.h"
35 #include "common/dout.h"
37 #include "rgw_rados.h"
38 #include "rgw_resolve.h"
41 #include "rgw_frontend.h"
42 #include "rgw_request.h"
43 #include "rgw_process.h"
44 #include "rgw_rest_user.h"
45 #include "rgw_rest_s3.h"
46 #include "rgw_os_lib.h"
48 #include "rgw_auth_s3.h"
50 #include "rgw_lib_frontend.h"
60 #define dout_subsys ceph_subsys_rgw
62 bool global_stop
= false;
68 static std::mutex librgw_mtx
;
72 class C_InitTimeout
: public Context
{
75 void finish(int r
) override
{
76 derr
<< "Initialization timeout, failed to initialize" << dendl
;
81 void RGWLibProcess::checkpoint()
86 #define MIN_EXPIRE_S 120
88 void RGWLibProcess::run()
90 /* write completion interval */
91 RGWLibFS::write_completion_interval_s
=
92 cct
->_conf
->rgw_nfs_write_completion_interval_s
;
94 /* start write timer */
95 RGWLibFS::write_timer
.resume();
99 lsubdout(cct
, rgw
, 5) << "RGWLibProcess GC" << dendl
;
101 /* dirent invalidate timeout--basically, the upper-bound on
102 * inconsistency with the S3 namespace */
103 auto expire_s
= cct
->_conf
->rgw_nfs_namespace_expire_secs
;
105 /* delay between gc cycles */
106 auto delay_s
= std::max(1, std::min(MIN_EXPIRE_S
, expire_s
/2));
108 unique_lock
uniq(mtx
);
111 for (auto iter
= mounted_fs
.begin(); iter
!= mounted_fs
.end();
113 RGWLibFS
* fs
= iter
->first
->ref();
119 goto restart
; /* invalidated */
122 std::this_thread::sleep_for(std::chrono::seconds(delay_s
));
126 void RGWLibProcess::handle_request(RGWRequest
* r
)
129 * invariant: valid requests are derived from RGWLibRequst
131 RGWLibRequest
* req
= static_cast<RGWLibRequest
*>(r
);
133 // XXX move RGWLibIO and timing setup into process_request
136 utime_t tm
= ceph_clock_now();
141 int ret
= process_request(req
, &io_ctx
);
143 /* we don't really care about return code */
144 dout(20) << "process_request() returned " << ret
<< dendl
;
148 } /* handle_request */
150 int RGWLibProcess::process_request(RGWLibRequest
* req
)
152 // XXX move RGWLibIO and timing setup into process_request
155 utime_t tm
= ceph_clock_now();
160 int ret
= process_request(req
, &io_ctx
);
162 /* we don't really care about return code */
163 dout(20) << "process_request() returned " << ret
<< dendl
;
166 } /* process_request */
168 static inline void abort_req(struct req_state
*s
, RGWOp
*op
, int err_no
)
173 /* XXX the dump_errno and dump_bucket_from_state behaviors in
174 * the abort_early (rgw_rest.cc) might be valuable, but aren't
175 * safe to call presently as they return HTTP data */
177 perfcounter
->inc(l_rgw_failed_req
);
180 int RGWLibProcess::process_request(RGWLibRequest
* req
, RGWLibIO
* io
)
183 bool should_log
= true; // XXX
185 dout(1) << "====== " << __func__
186 << " starting new request req=" << hex
<< req
<< dec
187 << " ======" << dendl
;
190 * invariant: valid requests are derived from RGWOp--well-formed
191 * requests should have assigned RGWRequest::op in their descendant
192 * constructor--if not, the compiler can find it, at the cost of
195 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
197 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
203 perfcounter
->inc(l_rgw_req
);
205 RGWEnv
& rgw_env
= io
->get_env();
208 * until major refactoring of req_state and req_info, we need
209 * to build their RGWEnv boilerplate from the RGWLibRequest,
210 * pre-staging any strings (HTTP_HOST) that provoke a crash when
214 /* XXX for now, use ""; could be a legit hostname, or, in future,
215 * perhaps a tenant (Yehuda) */
216 rgw_env
.set("HTTP_HOST", "");
218 /* XXX and -then- bloat up req_state with string copies from it */
219 struct req_state
rstate(req
->cct
, &rgw_env
, req
->get_user());
220 struct req_state
*s
= &rstate
;
225 RGWObjectCtx
rados_ctx(store
, s
); // XXX holds std::map
227 /* XXX and -then- stash req_state pointers everywhere they are needed */
228 ret
= req
->init(rgw_env
, &rados_ctx
, io
, s
);
230 dout(10) << "failed to initialize request" << dendl
;
231 abort_req(s
, op
, ret
);
235 /* req is-a RGWOp, currently initialized separately */
236 ret
= req
->op_init();
238 dout(10) << "failed to initialize RGWOp" << dendl
;
239 abort_req(s
, op
, ret
);
243 /* XXX authorize does less here then in the REST path, e.g.,
244 * the user's info is cached, but still incomplete */
245 req
->log(s
, "authorizing");
246 ret
= req
->authorize();
248 dout(10) << "failed to authorize request" << dendl
;
249 abort_req(s
, op
, ret
);
253 /* FIXME: remove this after switching all handlers to the new authentication
255 if (! s
->auth
.identity
) {
256 s
->auth
.identity
= rgw::auth::transform_old_authinfo(s
);
259 req
->log(s
, "reading op permissions");
260 ret
= req
->read_permissions(op
);
262 abort_req(s
, op
, ret
);
266 req
->log(s
, "init op");
267 ret
= op
->init_processing();
269 abort_req(s
, op
, ret
);
273 req
->log(s
, "verifying op mask");
274 ret
= op
->verify_op_mask();
276 abort_req(s
, op
, ret
);
280 req
->log(s
, "verifying op permissions");
281 ret
= op
->verify_permission();
283 if (s
->system_request
) {
284 dout(2) << "overriding permissions due to system operation" << dendl
;
285 } else if (s
->auth
.identity
->is_admin_of(s
->user
->user_id
)) {
286 dout(2) << "overriding permissions due to admin operation" << dendl
;
288 abort_req(s
, op
, ret
);
293 req
->log(s
, "verifying op params");
294 ret
= op
->verify_params();
296 abort_req(s
, op
, ret
);
300 req
->log(s
, "executing");
307 io
->complete_request();
308 } catch (rgw::io::Exception
& e
) {
309 dout(0) << "ERROR: io->complete_request() returned "
310 << e
.what() << dendl
;
313 rgw_log_op(store
, nullptr /* !rest */, s
,
314 (op
? op
->name() : "unknown"), olog
);
317 int http_ret
= s
->err
.http_ret
;
319 req
->log_format(s
, "http status=%d", http_ret
);
321 dout(1) << "====== " << __func__
322 << " req done req=" << hex
<< req
<< dec
<< " http_status="
324 << " ======" << dendl
;
326 return (ret
< 0 ? ret
: s
->err
.ret
);
327 } /* process_request */
329 int RGWLibProcess::start_request(RGWLibContinuedReq
* req
)
332 dout(1) << "====== " << __func__
333 << " starting new continued request req=" << hex
<< req
<< dec
334 << " ======" << dendl
;
337 * invariant: valid requests are derived from RGWOp--well-formed
338 * requests should have assigned RGWRequest::op in their descendant
339 * constructor--if not, the compiler can find it, at the cost of
342 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
344 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
348 struct req_state
* s
= req
->get_state();
350 /* req is-a RGWOp, currently initialized separately */
351 int ret
= req
->op_init();
353 dout(10) << "failed to initialize RGWOp" << dendl
;
354 abort_req(s
, op
, ret
);
358 /* XXX authorize does less here then in the REST path, e.g.,
359 * the user's info is cached, but still incomplete */
360 req
->log(s
, "authorizing");
361 ret
= req
->authorize();
363 dout(10) << "failed to authorize request" << dendl
;
364 abort_req(s
, op
, ret
);
368 /* FIXME: remove this after switching all handlers to the new authentication
370 if (! s
->auth
.identity
) {
371 s
->auth
.identity
= rgw::auth::transform_old_authinfo(s
);
374 req
->log(s
, "reading op permissions");
375 ret
= req
->read_permissions(op
);
377 abort_req(s
, op
, ret
);
381 req
->log(s
, "init op");
382 ret
= op
->init_processing();
384 abort_req(s
, op
, ret
);
388 req
->log(s
, "verifying op mask");
389 ret
= op
->verify_op_mask();
391 abort_req(s
, op
, ret
);
395 req
->log(s
, "verifying op permissions");
396 ret
= op
->verify_permission();
398 if (s
->system_request
) {
399 dout(2) << "overriding permissions due to system operation" << dendl
;
400 } else if (s
->auth
.identity
->is_admin_of(s
->user
->user_id
)) {
401 dout(2) << "overriding permissions due to admin operation" << dendl
;
403 abort_req(s
, op
, ret
);
408 req
->log(s
, "verifying op params");
409 ret
= op
->verify_params();
411 abort_req(s
, op
, ret
);
419 return (ret
< 0 ? ret
: s
->err
.ret
);
422 int RGWLibProcess::finish_request(RGWLibContinuedReq
* req
)
424 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
426 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
430 int ret
= req
->exec_finish();
431 int op_ret
= op
->get_ret();
433 dout(1) << "====== " << __func__
434 << " finishing continued request req=" << hex
<< req
<< dec
435 << " op status=" << op_ret
436 << " ======" << dendl
;
441 int RGWLibFrontend::init()
443 pprocess
= new RGWLibProcess(g_ceph_context
, &env
,
444 g_conf
->rgw_thread_pool_size
, conf
);
450 vector
<const char*> args
;
454 int RGWLib::init(vector
<const char*>& args
)
458 /* alternative default for module */
459 vector
<const char *> def_args
;
460 def_args
.push_back("--debug-rgw=1/5");
461 def_args
.push_back("--keyring=$rgw_data/keyring");
462 def_args
.push_back("--log-file=/var/log/radosgw/$cluster-$name.log");
464 cct
= global_init(&def_args
, args
,
465 CEPH_ENTITY_TYPE_CLIENT
,
466 CODE_ENVIRONMENT_DAEMON
,
467 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
470 SafeTimer
init_timer(g_ceph_context
, mutex
);
473 init_timer
.add_event_after(g_conf
->rgw_init_timeout
, new C_InitTimeout
);
476 common_init_finish(g_ceph_context
);
478 rgw_tools_init(g_ceph_context
);
482 store
= RGWStoreManager::get_storage(g_ceph_context
,
483 g_conf
->rgw_enable_gc_threads
,
484 g_conf
->rgw_enable_lc_threads
,
485 g_conf
->rgw_enable_quota_threads
,
486 g_conf
->rgw_run_sync_thread
,
487 g_conf
->rgw_dynamic_resharding
);
491 init_timer
.cancel_all_events();
492 init_timer
.shutdown();
495 derr
<< "Couldn't init storage provider (RADOS)" << dendl
;
499 r
= rgw_perf_start(g_ceph_context
);
501 rgw_rest_init(g_ceph_context
, store
, store
->get_zonegroup());
504 init_timer
.cancel_all_events();
505 init_timer
.shutdown();
511 const string
& ldap_uri
= store
->ctx()->_conf
->rgw_ldap_uri
;
512 const string
& ldap_binddn
= store
->ctx()->_conf
->rgw_ldap_binddn
;
513 const string
& ldap_searchdn
= store
->ctx()->_conf
->rgw_ldap_searchdn
;
514 const string
& ldap_searchfilter
= store
->ctx()->_conf
->rgw_ldap_searchfilter
;
515 const string
& ldap_dnattr
=
516 store
->ctx()->_conf
->rgw_ldap_dnattr
;
517 std::string ldap_bindpw
= parse_rgw_ldap_bindpw(store
->ctx());
519 ldh
= new rgw::LDAPHelper(ldap_uri
, ldap_binddn
, ldap_bindpw
.c_str(),
520 ldap_searchdn
, ldap_searchfilter
, ldap_dnattr
);
524 rgw_user_init(store
);
525 rgw_bucket_init(store
->meta_mgr
);
526 rgw_log_usage_init(g_ceph_context
, store
);
528 // XXX ex-RGWRESTMgr_lib, mgr->set_logging(true)
530 if (!g_conf
->rgw_ops_log_socket_path
.empty()) {
531 olog
= new OpsLogSocket(g_ceph_context
, g_conf
->rgw_ops_log_data_backlog
);
532 olog
->init(g_conf
->rgw_ops_log_socket_path
);
536 RGWProcessEnv env
= { store
, &rest
, olog
, port
};
538 string fe_count
{"0"};
539 fec
= new RGWFrontendConfig("rgwlib");
540 fe
= new RGWLibFrontend(env
, fec
);
542 map
<string
, string
> service_map_meta
;
543 service_map_meta
["pid"] = stringify(getpid());
544 service_map_meta
["frontend_type#" + fe_count
] = "rgw-nfs";
545 service_map_meta
["frontend_config#" + fe_count
] = fec
->get_config();
549 derr
<< "ERROR: failed initializing frontend" << dendl
;
555 r
= store
->register_to_service_map("rgw-nfs", service_map_meta
);
557 derr
<< "ERROR: failed to register to service map: " << cpp_strerror(-r
) << dendl
;
562 } /* RGWLib::init() */
566 derr
<< "shutting down" << dendl
;
576 rgw_log_usage_finalize();
580 RGWStoreManager::close_storage(store
);
583 rgw_shutdown_resolver();
585 rgw_perf_stop(g_ceph_context
);
587 dout(1) << "final shutdown" << dendl
;
591 } /* RGWLib::stop() */
593 int RGWLibIO::set_uid(RGWRados
*store
, const rgw_user
& uid
)
595 int ret
= rgw_get_user_info_by_uid(store
, uid
, user_info
, NULL
);
597 derr
<< "ERROR: failed reading user info: uid=" << uid
<< " ret="
603 int RGWLibRequest::read_permissions(RGWOp
* op
) {
604 /* bucket and object ops */
606 rgw_build_bucket_policies(rgwlib
.get_store(), get_state());
608 ldout(get_state()->cct
, 10) << "read_permissions (bucket policy) on "
609 << get_state()->bucket
<< ":"
610 << get_state()->object
611 << " only_bucket=" << only_bucket()
612 << " ret=" << ret
<< dendl
;
615 } else if (! only_bucket()) {
617 ret
= rgw_build_object_policies(rgwlib
.get_store(), get_state(),
618 op
->prefetch_data());
620 ldout(get_state()->cct
, 10) << "read_permissions (object policy) on"
621 << get_state()->bucket
<< ":"
622 << get_state()->object
623 << " ret=" << ret
<< dendl
;
629 } /* RGWLibRequest::read_permissions */
631 int RGWHandler_Lib::authorize()
635 * 2. anonymous access
639 * Much or all of this depends on handling the cached authorization
640 * correctly (e.g., dealing with keystone) at mount time.
642 s
->perm_mask
= RGW_PERM_FULL_CONTROL
;
644 // populate the owner info
645 s
->owner
.set_id(s
->user
->user_id
);
646 s
->owner
.set_name(s
->user
->display_name
);
649 } /* RGWHandler_Lib::authorize */
651 } /* namespace rgw */
655 int librgw_create(librgw_t
* rgw
, int argc
, char **argv
)
661 if (! g_ceph_context
) {
662 std::lock_guard
<std::mutex
> lg(librgw_mtx
);
663 if (! g_ceph_context
) {
664 vector
<const char*> args
;
665 std::vector
<std::string
> spl_args
;
666 // last non-0 argument will be split and consumed
668 const std::string spl_arg
{argv
[(--argc
)]};
669 get_str_vec(spl_arg
, " \t", spl_args
);
671 argv_to_vec(argc
, const_cast<const char**>(argv
), args
);
672 // append split args, if any
673 for (const auto& elt
: spl_args
) {
674 args
.push_back(elt
.c_str());
677 rc
= rgwlib
.init(args
);
681 *rgw
= g_ceph_context
->get();
686 void librgw_shutdown(librgw_t rgw
)
690 CephContext
* cct
= static_cast<CephContext
*>(rgw
);