]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_lib.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / rgw_lib.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 /*
5 * Ceph - scalable distributed file system
6 *
7 * Copyright (C) 2011 New Dream Network
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 */
15
16 #include <sys/types.h>
17 #include <string.h>
18 #include <chrono>
19
20 #include "include/rados/librgw.h"
21 #include "rgw_acl.h"
22
23 #include "include/str_list.h"
24 #include "global/signal_handler.h"
25 #include "common/Timer.h"
26 #include "common/WorkQueue.h"
27 #include "common/ceph_argparse.h"
28 #include "common/ceph_context.h"
29 #include "common/common_init.h"
30 #include "common/dout.h"
31
32 #include "rgw_op.h"
33 #include "rgw_rest.h"
34 #include "rgw_log.h"
35 #include "rgw_frontend.h"
36 #include "rgw_request.h"
37 #include "rgw_process.h"
38 #include "rgw_auth.h"
39 #include "rgw_lib.h"
40 #include "rgw_lib_frontend.h"
41 #include "rgw_perf_counters.h"
42 #include "rgw_signal.h"
43 #include "rgw_main.h"
44
45 #include <errno.h>
46 #include <thread>
47 #include <string>
48 #include <mutex>
49
50 #define dout_subsys ceph_subsys_rgw
51
52 using namespace std;
53
54 namespace rgw {
55
56 RGWLib* g_rgwlib = nullptr;
57
58 class C_InitTimeout : public Context {
59 public:
60 C_InitTimeout() {}
61 void finish(int r) override {
62 derr << "Initialization timeout, failed to initialize" << dendl;
63 exit(1);
64 }
65 };
66
67 void RGWLibProcess::checkpoint()
68 {
69 m_tp.drain(&req_wq);
70 }
71
72 #define MIN_EXPIRE_S 120
73
74 void RGWLibProcess::run()
75 {
76 /* write completion interval */
77 RGWLibFS::write_completion_interval_s =
78 cct->_conf->rgw_nfs_write_completion_interval_s;
79
80 /* start write timer */
81 RGWLibFS::write_timer.resume();
82
83 /* gc loop */
84 while (! shutdown) {
85 lsubdout(cct, rgw, 5) << "RGWLibProcess GC" << dendl;
86
87 /* dirent invalidate timeout--basically, the upper-bound on
88 * inconsistency with the S3 namespace */
89 auto expire_s = cct->_conf->rgw_nfs_namespace_expire_secs;
90
91 /* delay between gc cycles */
92 auto delay_s = std::max(int64_t(1), std::min(int64_t(MIN_EXPIRE_S), expire_s/2));
93
94 unique_lock uniq(mtx);
95 restart:
96 int cur_gen = gen;
97 for (auto iter = mounted_fs.begin(); iter != mounted_fs.end();
98 ++iter) {
99 RGWLibFS* fs = iter->first->ref();
100 uniq.unlock();
101 fs->gc();
102 const DoutPrefix dp(cct, dout_subsys, "librgw: ");
103 fs->update_user(&dp);
104 fs->rele();
105 uniq.lock();
106 if (cur_gen != gen)
107 goto restart; /* invalidated */
108 }
109 cv.wait_for(uniq, std::chrono::seconds(delay_s));
110 uniq.unlock();
111 }
112 }
113
114 void RGWLibProcess::handle_request(const DoutPrefixProvider *dpp, RGWRequest* r)
115 {
116 /*
117 * invariant: valid requests are derived from RGWLibRequst
118 */
119 RGWLibRequest* req = static_cast<RGWLibRequest*>(r);
120
121 // XXX move RGWLibIO and timing setup into process_request
122
123 #if 0 /* XXX */
124 utime_t tm = ceph_clock_now();
125 #endif
126
127 RGWLibIO io_ctx;
128
129 int ret = process_request(req, &io_ctx);
130 if (ret < 0) {
131 /* we don't really care about return code */
132 dout(20) << "process_request() returned " << ret << dendl;
133
134 }
135 delete req;
136 } /* handle_request */
137
138 int RGWLibProcess::process_request(RGWLibRequest* req)
139 {
140 // XXX move RGWLibIO and timing setup into process_request
141
142 #if 0 /* XXX */
143 utime_t tm = ceph_clock_now();
144 #endif
145
146 RGWLibIO io_ctx;
147
148 int ret = process_request(req, &io_ctx);
149 if (ret < 0) {
150 /* we don't really care about return code */
151 dout(20) << "process_request() returned " << ret << dendl;
152 }
153 return ret;
154 } /* process_request */
155
156 static inline void abort_req(req_state *s, RGWOp *op, int err_no)
157 {
158 if (!s)
159 return;
160
161 /* XXX the dump_errno and dump_bucket_from_state behaviors in
162 * the abort_early (rgw_rest.cc) might be valuable, but aren't
163 * safe to call presently as they return HTTP data */
164
165 perfcounter->inc(l_rgw_failed_req);
166 } /* abort_req */
167
168 int RGWLibProcess::process_request(RGWLibRequest* req, RGWLibIO* io)
169 {
170 int ret = 0;
171 bool should_log = true; // XXX
172
173 dout(1) << "====== " << __func__
174 << " starting new request req=" << hex << req << dec
175 << " ======" << dendl;
176
177 /*
178 * invariant: valid requests are derived from RGWOp--well-formed
179 * requests should have assigned RGWRequest::op in their descendant
180 * constructor--if not, the compiler can find it, at the cost of
181 * a runtime check
182 */
183 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
184 if (! op) {
185 ldpp_dout(op, 1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
186 return -EINVAL;
187 }
188
189 io->init(req->cct);
190
191 perfcounter->inc(l_rgw_req);
192
193 RGWEnv& rgw_env = io->get_env();
194
195 /* XXX
196 * until major refactoring of req_state and req_info, we need
197 * to build their RGWEnv boilerplate from the RGWLibRequest,
198 * pre-staging any strings (HTTP_HOST) that provoke a crash when
199 * not found
200 */
201
202 /* XXX for now, use ""; could be a legit hostname, or, in future,
203 * perhaps a tenant (Yehuda) */
204 rgw_env.set("HTTP_HOST", "");
205
206 /* XXX and -then- bloat up req_state with string copies from it */
207 req_state rstate(req->cct, env, &rgw_env, req->id);
208 req_state *s = &rstate;
209
210 // XXX fix this
211 s->cio = io;
212
213 /* XXX and -then- stash req_state pointers everywhere they are needed */
214 ret = req->init(rgw_env, env.driver, io, s);
215 if (ret < 0) {
216 ldpp_dout(op, 10) << "failed to initialize request" << dendl;
217 abort_req(s, op, ret);
218 goto done;
219 }
220
221 /* req is-a RGWOp, currently initialized separately */
222 ret = req->op_init();
223 if (ret < 0) {
224 dout(10) << "failed to initialize RGWOp" << dendl;
225 abort_req(s, op, ret);
226 goto done;
227 }
228
229 /* now expected by rgw_log_op() */
230 rgw_env.set("REQUEST_METHOD", s->info.method);
231 rgw_env.set("REQUEST_URI", s->info.request_uri);
232 rgw_env.set("QUERY_STRING", "");
233
234 try {
235 /* XXX authorize does less here then in the REST path, e.g.,
236 * the user's info is cached, but still incomplete */
237 ldpp_dout(s, 2) << "authorizing" << dendl;
238 ret = req->authorize(op, null_yield);
239 if (ret < 0) {
240 dout(10) << "failed to authorize request" << dendl;
241 abort_req(s, op, ret);
242 goto done;
243 }
244
245 /* FIXME: remove this after switching all handlers to the new
246 * authentication infrastructure. */
247 if (! s->auth.identity) {
248 s->auth.identity = rgw::auth::transform_old_authinfo(s);
249 }
250
251 ldpp_dout(s, 2) << "reading op permissions" << dendl;
252 ret = req->read_permissions(op, null_yield);
253 if (ret < 0) {
254 abort_req(s, op, ret);
255 goto done;
256 }
257
258 ldpp_dout(s, 2) << "init op" << dendl;
259 ret = op->init_processing(null_yield);
260 if (ret < 0) {
261 abort_req(s, op, ret);
262 goto done;
263 }
264
265 ldpp_dout(s, 2) << "verifying op mask" << dendl;
266 ret = op->verify_op_mask();
267 if (ret < 0) {
268 abort_req(s, op, ret);
269 goto done;
270 }
271
272 ldpp_dout(s, 2) << "verifying op permissions" << dendl;
273 ret = op->verify_permission(null_yield);
274 if (ret < 0) {
275 if (s->system_request) {
276 ldpp_dout(op, 2) << "overriding permissions due to system operation" << dendl;
277 } else if (s->auth.identity->is_admin_of(s->user->get_id())) {
278 ldpp_dout(op, 2) << "overriding permissions due to admin operation" << dendl;
279 } else {
280 abort_req(s, op, ret);
281 goto done;
282 }
283 }
284
285 ldpp_dout(s, 2) << "verifying op params" << dendl;
286 ret = op->verify_params();
287 if (ret < 0) {
288 abort_req(s, op, ret);
289 goto done;
290 }
291
292 ldpp_dout(s, 2) << "executing" << dendl;
293 op->pre_exec();
294 op->execute(null_yield);
295 op->complete();
296
297 } catch (const ceph::crypto::DigestException& e) {
298 dout(0) << "authentication failed" << e.what() << dendl;
299 abort_req(s, op, -ERR_INVALID_SECRET_KEY);
300 }
301
302 done:
303 try {
304 io->complete_request();
305 } catch (rgw::io::Exception& e) {
306 dout(0) << "ERROR: io->complete_request() returned "
307 << e.what() << dendl;
308 }
309 if (should_log) {
310 rgw_log_op(nullptr /* !rest */, s, op, env.olog);
311 }
312
313 int http_ret = s->err.http_ret;
314
315 ldpp_dout(s, 2) << "http status=" << http_ret << dendl;
316
317 ldpp_dout(op, 1) << "====== " << __func__
318 << " req done req=" << hex << req << dec << " http_status="
319 << http_ret
320 << " ======" << dendl;
321
322 return (ret < 0 ? ret : s->err.ret);
323 } /* process_request */
324
325 int RGWLibProcess::start_request(RGWLibContinuedReq* req)
326 {
327
328 dout(1) << "====== " << __func__
329 << " starting new continued request req=" << hex << req << dec
330 << " ======" << dendl;
331
332 /*
333 * invariant: valid requests are derived from RGWOp--well-formed
334 * requests should have assigned RGWRequest::op in their descendant
335 * constructor--if not, the compiler can find it, at the cost of
336 * a runtime check
337 */
338 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
339 if (! op) {
340 ldpp_dout(op, 1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
341 return -EINVAL;
342 }
343
344 req_state* s = req->get_state();
345 RGWLibIO& io_ctx = req->get_io();
346 RGWEnv& rgw_env = io_ctx.get_env();
347
348 rgw_env.set("HTTP_HOST", "");
349
350 int ret = req->init(rgw_env, env.driver, &io_ctx, s);
351 if (ret < 0) {
352 ldpp_dout(op, 10) << "failed to initialize request" << dendl;
353 abort_req(s, op, ret);
354 goto done;
355 }
356
357 /* req is-a RGWOp, currently initialized separately */
358 ret = req->op_init();
359 if (ret < 0) {
360 dout(10) << "failed to initialize RGWOp" << dendl;
361 abort_req(s, op, ret);
362 goto done;
363 }
364
365 /* XXX authorize does less here then in the REST path, e.g.,
366 * the user's info is cached, but still incomplete */
367 ldpp_dout(s, 2) << "authorizing" << dendl;
368 ret = req->authorize(op, null_yield);
369 if (ret < 0) {
370 dout(10) << "failed to authorize request" << dendl;
371 abort_req(s, op, ret);
372 goto done;
373 }
374
375 /* FIXME: remove this after switching all handlers to the new authentication
376 * infrastructure. */
377 if (! s->auth.identity) {
378 s->auth.identity = rgw::auth::transform_old_authinfo(s);
379 }
380
381 ldpp_dout(s, 2) << "reading op permissions" << dendl;
382 ret = req->read_permissions(op, null_yield);
383 if (ret < 0) {
384 abort_req(s, op, ret);
385 goto done;
386 }
387
388 ldpp_dout(s, 2) << "init op" << dendl;
389 ret = op->init_processing(null_yield);
390 if (ret < 0) {
391 abort_req(s, op, ret);
392 goto done;
393 }
394
395 ldpp_dout(s, 2) << "verifying op mask" << dendl;
396 ret = op->verify_op_mask();
397 if (ret < 0) {
398 abort_req(s, op, ret);
399 goto done;
400 }
401
402 ldpp_dout(s, 2) << "verifying op permissions" << dendl;
403 ret = op->verify_permission(null_yield);
404 if (ret < 0) {
405 if (s->system_request) {
406 ldpp_dout(op, 2) << "overriding permissions due to system operation" << dendl;
407 } else if (s->auth.identity->is_admin_of(s->user->get_id())) {
408 ldpp_dout(op, 2) << "overriding permissions due to admin operation" << dendl;
409 } else {
410 abort_req(s, op, ret);
411 goto done;
412 }
413 }
414
415 ldpp_dout(s, 2) << "verifying op params" << dendl;
416 ret = op->verify_params();
417 if (ret < 0) {
418 abort_req(s, op, ret);
419 goto done;
420 }
421
422 op->pre_exec();
423 req->exec_start();
424
425 done:
426 return (ret < 0 ? ret : s->err.ret);
427 }
428
429 int RGWLibProcess::finish_request(RGWLibContinuedReq* req)
430 {
431 RGWOp *op = (req->op) ? req->op : dynamic_cast<RGWOp*>(req);
432 if (! op) {
433 ldpp_dout(op, 1) << "failed to derive cognate RGWOp (invalid op?)" << dendl;
434 return -EINVAL;
435 }
436
437 int ret = req->exec_finish();
438 int op_ret = op->get_ret();
439
440 ldpp_dout(op, 1) << "====== " << __func__
441 << " finishing continued request req=" << hex << req << dec
442 << " op status=" << op_ret
443 << " ======" << dendl;
444
445 perfcounter->inc(l_rgw_req);
446
447 return ret;
448 }
449
450 int RGWLibFrontend::init()
451 {
452 std::string uri_prefix; // empty
453 pprocess = new RGWLibProcess(g_ceph_context, env,
454 g_conf()->rgw_thread_pool_size, uri_prefix, conf);
455 return 0;
456 }
457
458 void RGWLib::set_fe(rgw::RGWLibFrontend* fe)
459 {
460 this->fe = fe;
461 }
462
463 int RGWLib::init()
464 {
465 vector<const char*> args;
466 return init(args);
467 }
468
469 int RGWLib::init(vector<const char*>& args)
470 {
471 /* alternative default for module */
472 map<std::string,std::string> defaults = {
473 { "debug_rgw", "1/5" },
474 { "keyring", "$rgw_data/keyring" },
475 { "log_file", "/var/log/radosgw/$cluster-$name.log" },
476 { "objecter_inflight_ops", "24576" },
477 // require a secure mon connection by default
478 { "ms_mon_client_mode", "secure" },
479 { "auth_client_required", "cephx" },
480 };
481
482 cct = rgw_global_init(&defaults, args,
483 CEPH_ENTITY_TYPE_CLIENT,
484 CODE_ENVIRONMENT_DAEMON,
485 CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS);
486
487 ceph::mutex mutex = ceph::make_mutex("main");
488 SafeTimer init_timer(g_ceph_context, mutex);
489 init_timer.init();
490 mutex.lock();
491 init_timer.add_event_after(g_conf()->rgw_init_timeout, new C_InitTimeout);
492 mutex.unlock();
493
494 /* stage all front-ends (before common-init-finish) */
495 main.init_frontends1(true /* nfs */);
496
497 common_init_finish(g_ceph_context);
498
499 main.init_perfcounters();
500 main.init_http_clients();
501
502 main.init_storage();
503 if (! main.get_driver()) {
504 mutex.lock();
505 init_timer.cancel_all_events();
506 init_timer.shutdown();
507 mutex.unlock();
508
509 derr << "Couldn't init storage provider (RADOS)" << dendl;
510 return -EIO;
511 }
512
513 main.cond_init_apis();
514
515 mutex.lock();
516 init_timer.cancel_all_events();
517 init_timer.shutdown();
518 mutex.unlock();
519
520 main.init_ldap();
521 main.init_opslog();
522
523 init_async_signal_handler();
524 register_async_signal_handler(SIGUSR1, rgw::signal::handle_sigterm);
525
526 main.init_tracepoints();
527 main.init_frontends2(this /* rgwlib */);
528 main.init_notification_endpoints();
529 main.init_lua();
530
531 return 0;
532 } /* RGWLib::init() */
533
534 int RGWLib::stop()
535 {
536 derr << "shutting down" << dendl;
537
538 const auto finalize_async_signals = []() {
539 unregister_async_signal_handler(SIGUSR1, rgw::signal::handle_sigterm);
540 shutdown_async_signal_handler();
541 };
542
543 main.shutdown(finalize_async_signals);
544
545 return 0;
546 } /* RGWLib::stop() */
547
548 int RGWLibIO::set_uid(rgw::sal::Driver* driver, const rgw_user& uid)
549 {
550 const DoutPrefix dp(driver->ctx(), dout_subsys, "librgw: ");
551 std::unique_ptr<rgw::sal::User> user = driver->get_user(uid);
552 /* object exists, but policy is broken */
553 int ret = user->load_user(&dp, null_yield);
554 if (ret < 0) {
555 derr << "ERROR: failed reading user info: uid=" << uid << " ret="
556 << ret << dendl;
557 }
558 user_info = user->get_info();
559 return ret;
560 }
561
562 int RGWLibRequest::read_permissions(RGWOp* op, optional_yield y) {
563 /* bucket and object ops */
564 int ret =
565 rgw_build_bucket_policies(op, g_rgwlib->get_driver(), get_state(), y);
566 if (ret < 0) {
567 ldpp_dout(op, 10) << "read_permissions (bucket policy) on "
568 << get_state()->bucket << ":"
569 << get_state()->object
570 << " only_bucket=" << only_bucket()
571 << " ret=" << ret << dendl;
572 if (ret == -ENODATA)
573 ret = -EACCES;
574 } else if (! only_bucket()) {
575 /* object ops */
576 ret = rgw_build_object_policies(op, g_rgwlib->get_driver(), get_state(),
577 op->prefetch_data(), y);
578 if (ret < 0) {
579 ldpp_dout(op, 10) << "read_permissions (object policy) on"
580 << get_state()->bucket << ":"
581 << get_state()->object
582 << " ret=" << ret << dendl;
583 if (ret == -ENODATA)
584 ret = -EACCES;
585 }
586 }
587 return ret;
588 } /* RGWLibRequest::read_permissions */
589
590 int RGWHandler_Lib::authorize(const DoutPrefixProvider *dpp, optional_yield y)
591 {
592 /* TODO: handle
593 * 1. subusers
594 * 2. anonymous access
595 * 3. system access
596 * 4. ?
597 *
598 * Much or all of this depends on handling the cached authorization
599 * correctly (e.g., dealing with keystone) at mount time.
600 */
601 s->perm_mask = RGW_PERM_FULL_CONTROL;
602
603 // populate the owner info
604 s->owner.set_id(s->user->get_id());
605 s->owner.set_name(s->user->get_display_name());
606
607 return 0;
608 } /* RGWHandler_Lib::authorize */
609
610 } /* namespace rgw */