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 "global/global_init.h"
26 #include "common/config.h"
27 #include "common/errno.h"
28 #include "common/Timer.h"
29 #include "common/Throttle.h"
30 #include "common/WorkQueue.h"
31 #include "common/ceph_argparse.h"
32 #include "common/ceph_context.h"
33 #include "common/common_init.h"
34 #include "common/dout.h"
36 #include "rgw_rados.h"
37 #include "rgw_resolve.h"
40 #include "rgw_frontend.h"
41 #include "rgw_request.h"
42 #include "rgw_process.h"
43 #include "rgw_rest_user.h"
44 #include "rgw_rest_s3.h"
45 #include "rgw_os_lib.h"
47 #include "rgw_auth_s3.h"
49 #include "rgw_lib_frontend.h"
59 #define dout_subsys ceph_subsys_rgw
61 bool global_stop
= false;
67 static std::mutex librgw_mtx
;
71 class C_InitTimeout
: public Context
{
74 void finish(int r
) override
{
75 derr
<< "Initialization timeout, failed to initialize" << dendl
;
80 void RGWLibProcess::checkpoint()
85 #define MIN_EXPIRE_S 120
87 void RGWLibProcess::run()
89 /* write completion interval */
90 RGWLibFS::write_completion_interval_s
=
91 cct
->_conf
->rgw_nfs_write_completion_interval_s
;
93 /* start write timer */
94 RGWLibFS::write_timer
.resume();
98 lsubdout(cct
, rgw
, 5) << "RGWLibProcess GC" << dendl
;
100 /* dirent invalidate timeout--basically, the upper-bound on
101 * inconsistency with the S3 namespace */
102 auto expire_s
= cct
->_conf
->rgw_nfs_namespace_expire_secs
;
104 /* delay between gc cycles */
105 auto delay_s
= std::max(1, std::min(MIN_EXPIRE_S
, expire_s
/2));
107 unique_lock
uniq(mtx
);
110 for (auto iter
= mounted_fs
.begin(); iter
!= mounted_fs
.end();
112 RGWLibFS
* fs
= iter
->first
->ref();
118 goto restart
; /* invalidated */
121 std::this_thread::sleep_for(std::chrono::seconds(delay_s
));
125 void RGWLibProcess::handle_request(RGWRequest
* r
)
128 * invariant: valid requests are derived from RGWLibRequst
130 RGWLibRequest
* req
= static_cast<RGWLibRequest
*>(r
);
132 // XXX move RGWLibIO and timing setup into process_request
135 utime_t tm
= ceph_clock_now();
140 int ret
= process_request(req
, &io_ctx
);
142 /* we don't really care about return code */
143 dout(20) << "process_request() returned " << ret
<< dendl
;
147 } /* handle_request */
149 int RGWLibProcess::process_request(RGWLibRequest
* req
)
151 // XXX move RGWLibIO and timing setup into process_request
154 utime_t tm
= ceph_clock_now();
159 int ret
= process_request(req
, &io_ctx
);
161 /* we don't really care about return code */
162 dout(20) << "process_request() returned " << ret
<< dendl
;
165 } /* process_request */
167 static inline void abort_req(struct req_state
*s
, RGWOp
*op
, int err_no
)
172 /* XXX the dump_errno and dump_bucket_from_state behaviors in
173 * the abort_early (rgw_rest.cc) might be valuable, but aren't
174 * safe to call presently as they return HTTP data */
176 perfcounter
->inc(l_rgw_failed_req
);
179 int RGWLibProcess::process_request(RGWLibRequest
* req
, RGWLibIO
* io
)
182 bool should_log
= true; // XXX
184 dout(1) << "====== " << __func__
185 << " starting new request req=" << hex
<< req
<< dec
186 << " ======" << dendl
;
189 * invariant: valid requests are derived from RGWOp--well-formed
190 * requests should have assigned RGWRequest::op in their descendant
191 * constructor--if not, the compiler can find it, at the cost of
194 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
196 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
202 perfcounter
->inc(l_rgw_req
);
204 RGWEnv
& rgw_env
= io
->get_env();
207 * until major refactoring of req_state and req_info, we need
208 * to build their RGWEnv boilerplate from the RGWLibRequest,
209 * pre-staging any strings (HTTP_HOST) that provoke a crash when
213 /* XXX for now, use ""; could be a legit hostname, or, in future,
214 * perhaps a tenant (Yehuda) */
215 rgw_env
.set("HTTP_HOST", "");
217 /* XXX and -then- bloat up req_state with string copies from it */
218 struct req_state
rstate(req
->cct
, &rgw_env
, req
->get_user());
219 struct req_state
*s
= &rstate
;
224 RGWObjectCtx
rados_ctx(store
, s
); // XXX holds std::map
226 /* XXX and -then- stash req_state pointers everywhere they are needed */
227 ret
= req
->init(rgw_env
, &rados_ctx
, io
, s
);
229 dout(10) << "failed to initialize request" << dendl
;
230 abort_req(s
, op
, ret
);
234 /* req is-a RGWOp, currently initialized separately */
235 ret
= req
->op_init();
237 dout(10) << "failed to initialize RGWOp" << dendl
;
238 abort_req(s
, op
, ret
);
242 /* XXX authorize does less here then in the REST path, e.g.,
243 * the user's info is cached, but still incomplete */
244 req
->log(s
, "authorizing");
245 ret
= req
->authorize();
247 dout(10) << "failed to authorize request" << dendl
;
248 abort_req(s
, op
, ret
);
252 /* FIXME: remove this after switching all handlers to the new authentication
254 if (! s
->auth
.identity
) {
255 s
->auth
.identity
= rgw::auth::transform_old_authinfo(s
);
258 req
->log(s
, "reading op permissions");
259 ret
= req
->read_permissions(op
);
261 abort_req(s
, op
, ret
);
265 req
->log(s
, "init op");
266 ret
= op
->init_processing();
268 abort_req(s
, op
, ret
);
272 req
->log(s
, "verifying op mask");
273 ret
= op
->verify_op_mask();
275 abort_req(s
, op
, ret
);
279 req
->log(s
, "verifying op permissions");
280 ret
= op
->verify_permission();
282 if (s
->system_request
) {
283 dout(2) << "overriding permissions due to system operation" << dendl
;
284 } else if (s
->auth
.identity
->is_admin_of(s
->user
->user_id
)) {
285 dout(2) << "overriding permissions due to admin operation" << dendl
;
287 abort_req(s
, op
, ret
);
292 req
->log(s
, "verifying op params");
293 ret
= op
->verify_params();
295 abort_req(s
, op
, ret
);
299 req
->log(s
, "executing");
306 io
->complete_request();
307 } catch (rgw::io::Exception
& e
) {
308 dout(0) << "ERROR: io->complete_request() returned "
309 << e
.what() << dendl
;
312 rgw_log_op(store
, nullptr /* !rest */, s
,
313 (op
? op
->name() : "unknown"), olog
);
316 int http_ret
= s
->err
.http_ret
;
318 req
->log_format(s
, "http status=%d", http_ret
);
320 dout(1) << "====== " << __func__
321 << " req done req=" << hex
<< req
<< dec
<< " http_status="
323 << " ======" << dendl
;
325 return (ret
< 0 ? ret
: s
->err
.ret
);
326 } /* process_request */
328 int RGWLibProcess::start_request(RGWLibContinuedReq
* req
)
331 dout(1) << "====== " << __func__
332 << " starting new continued request req=" << hex
<< req
<< dec
333 << " ======" << dendl
;
336 * invariant: valid requests are derived from RGWOp--well-formed
337 * requests should have assigned RGWRequest::op in their descendant
338 * constructor--if not, the compiler can find it, at the cost of
341 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
343 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
347 struct req_state
* s
= req
->get_state();
349 /* req is-a RGWOp, currently initialized separately */
350 int ret
= req
->op_init();
352 dout(10) << "failed to initialize RGWOp" << dendl
;
353 abort_req(s
, op
, ret
);
357 /* XXX authorize does less here then in the REST path, e.g.,
358 * the user's info is cached, but still incomplete */
359 req
->log(s
, "authorizing");
360 ret
= req
->authorize();
362 dout(10) << "failed to authorize request" << dendl
;
363 abort_req(s
, op
, ret
);
367 /* FIXME: remove this after switching all handlers to the new authentication
369 if (! s
->auth
.identity
) {
370 s
->auth
.identity
= rgw::auth::transform_old_authinfo(s
);
373 req
->log(s
, "reading op permissions");
374 ret
= req
->read_permissions(op
);
376 abort_req(s
, op
, ret
);
380 req
->log(s
, "init op");
381 ret
= op
->init_processing();
383 abort_req(s
, op
, ret
);
387 req
->log(s
, "verifying op mask");
388 ret
= op
->verify_op_mask();
390 abort_req(s
, op
, ret
);
394 req
->log(s
, "verifying op permissions");
395 ret
= op
->verify_permission();
397 if (s
->system_request
) {
398 dout(2) << "overriding permissions due to system operation" << dendl
;
399 } else if (s
->auth
.identity
->is_admin_of(s
->user
->user_id
)) {
400 dout(2) << "overriding permissions due to admin operation" << dendl
;
402 abort_req(s
, op
, ret
);
407 req
->log(s
, "verifying op params");
408 ret
= op
->verify_params();
410 abort_req(s
, op
, ret
);
418 return (ret
< 0 ? ret
: s
->err
.ret
);
421 int RGWLibProcess::finish_request(RGWLibContinuedReq
* req
)
423 RGWOp
*op
= (req
->op
) ? req
->op
: dynamic_cast<RGWOp
*>(req
);
425 dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl
;
429 int ret
= req
->exec_finish();
430 int op_ret
= op
->get_ret();
432 dout(1) << "====== " << __func__
433 << " finishing continued request req=" << hex
<< req
<< dec
434 << " op status=" << op_ret
435 << " ======" << dendl
;
440 int RGWLibFrontend::init()
442 pprocess
= new RGWLibProcess(g_ceph_context
, &env
,
443 g_conf
->rgw_thread_pool_size
, conf
);
449 vector
<const char*> args
;
453 int RGWLib::init(vector
<const char*>& args
)
457 /* alternative default for module */
458 vector
<const char *> def_args
;
459 def_args
.push_back("--debug-rgw=1/5");
460 def_args
.push_back("--keyring=$rgw_data/keyring");
461 def_args
.push_back("--log-file=/var/log/radosgw/$cluster-$name.log");
463 cct
= global_init(&def_args
, args
,
464 CEPH_ENTITY_TYPE_CLIENT
,
465 CODE_ENVIRONMENT_DAEMON
,
466 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS
);
469 SafeTimer
init_timer(g_ceph_context
, mutex
);
472 init_timer
.add_event_after(g_conf
->rgw_init_timeout
, new C_InitTimeout
);
475 common_init_finish(g_ceph_context
);
477 rgw_tools_init(g_ceph_context
);
481 store
= RGWStoreManager::get_storage(g_ceph_context
,
482 g_conf
->rgw_enable_gc_threads
,
483 g_conf
->rgw_enable_lc_threads
,
484 g_conf
->rgw_enable_quota_threads
,
485 g_conf
->rgw_run_sync_thread
,
486 g_conf
->rgw_dynamic_resharding
);
490 init_timer
.cancel_all_events();
491 init_timer
.shutdown();
494 derr
<< "Couldn't init storage provider (RADOS)" << dendl
;
498 r
= rgw_perf_start(g_ceph_context
);
500 rgw_rest_init(g_ceph_context
, store
, store
->get_zonegroup());
503 init_timer
.cancel_all_events();
504 init_timer
.shutdown();
510 const string
& ldap_uri
= store
->ctx()->_conf
->rgw_ldap_uri
;
511 const string
& ldap_binddn
= store
->ctx()->_conf
->rgw_ldap_binddn
;
512 const string
& ldap_searchdn
= store
->ctx()->_conf
->rgw_ldap_searchdn
;
513 const string
& ldap_searchfilter
= store
->ctx()->_conf
->rgw_ldap_searchfilter
;
514 const string
& ldap_dnattr
=
515 store
->ctx()->_conf
->rgw_ldap_dnattr
;
516 std::string ldap_bindpw
= parse_rgw_ldap_bindpw(store
->ctx());
518 ldh
= new rgw::LDAPHelper(ldap_uri
, ldap_binddn
, ldap_bindpw
.c_str(),
519 ldap_searchdn
, ldap_searchfilter
, ldap_dnattr
);
523 rgw_user_init(store
);
524 rgw_bucket_init(store
->meta_mgr
);
525 rgw_log_usage_init(g_ceph_context
, store
);
527 // XXX ex-RGWRESTMgr_lib, mgr->set_logging(true)
529 if (!g_conf
->rgw_ops_log_socket_path
.empty()) {
530 olog
= new OpsLogSocket(g_ceph_context
, g_conf
->rgw_ops_log_data_backlog
);
531 olog
->init(g_conf
->rgw_ops_log_socket_path
);
535 RGWProcessEnv env
= { store
, &rest
, olog
, port
};
537 fec
= new RGWFrontendConfig("rgwlib");
538 fe
= new RGWLibFrontend(env
, fec
);
542 derr
<< "ERROR: failed initializing frontend" << dendl
;
549 } /* RGWLib::init() */
553 derr
<< "shutting down" << dendl
;
563 rgw_log_usage_finalize();
567 RGWStoreManager::close_storage(store
);
570 rgw_shutdown_resolver();
572 rgw_perf_stop(g_ceph_context
);
574 dout(1) << "final shutdown" << dendl
;
578 } /* RGWLib::stop() */
580 int RGWLibIO::set_uid(RGWRados
*store
, const rgw_user
& uid
)
582 int ret
= rgw_get_user_info_by_uid(store
, uid
, user_info
, NULL
);
584 derr
<< "ERROR: failed reading user info: uid=" << uid
<< " ret="
590 int RGWLibRequest::read_permissions(RGWOp
* op
) {
591 /* bucket and object ops */
593 rgw_build_bucket_policies(rgwlib
.get_store(), get_state());
595 ldout(get_state()->cct
, 10) << "read_permissions (bucket policy) on "
596 << get_state()->bucket
<< ":"
597 << get_state()->object
598 << " only_bucket=" << only_bucket()
599 << " ret=" << ret
<< dendl
;
602 } else if (! only_bucket()) {
604 ret
= rgw_build_object_policies(rgwlib
.get_store(), get_state(),
605 op
->prefetch_data());
607 ldout(get_state()->cct
, 10) << "read_permissions (object policy) on"
608 << get_state()->bucket
<< ":"
609 << get_state()->object
610 << " ret=" << ret
<< dendl
;
616 } /* RGWLibRequest::read_permissions */
618 int RGWHandler_Lib::authorize()
622 * 2. anonymous access
626 * Much or all of this depends on handling the cached authorization
627 * correctly (e.g., dealing with keystone) at mount time.
629 s
->perm_mask
= RGW_PERM_FULL_CONTROL
;
631 // populate the owner info
632 s
->owner
.set_id(s
->user
->user_id
);
633 s
->owner
.set_name(s
->user
->display_name
);
636 } /* RGWHandler_Lib::authorize */
638 } /* namespace rgw */
642 int librgw_create(librgw_t
* rgw
, int argc
, char **argv
)
648 if (! g_ceph_context
) {
649 std::lock_guard
<std::mutex
> lg(librgw_mtx
);
650 if (! g_ceph_context
) {
651 vector
<const char*> args
;
652 std::vector
<std::string
> spl_args
;
653 // last non-0 argument will be split and consumed
655 const std::string spl_arg
{argv
[(--argc
)]};
656 get_str_vec(spl_arg
, " \t", spl_args
);
658 argv_to_vec(argc
, const_cast<const char**>(argv
), args
);
659 // append split args, if any
660 for (const auto& elt
: spl_args
) {
661 args
.push_back(elt
.c_str());
664 rc
= rgwlib
.init(args
);
668 *rgw
= g_ceph_context
->get();
673 void librgw_shutdown(librgw_t rgw
)
677 CephContext
* cct
= static_cast<CephContext
*>(rgw
);