]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_main.cc
update sources to 12.2.10
[ceph.git] / ceph / src / rgw / rgw_main.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#include <stdlib.h>
5#include <stdio.h>
6#include <string.h>
7#include <stdarg.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <errno.h>
12#include <signal.h>
13
7c673cae
FG
14#include <boost/intrusive_ptr.hpp>
15
16#include "acconfig.h"
17
18#include "common/ceph_argparse.h"
19#include "global/global_init.h"
20#include "global/signal_handler.h"
21#include "common/config.h"
22#include "common/errno.h"
23#include "common/Timer.h"
24#include "common/safe_io.h"
25#include "include/compat.h"
26#include "include/str_list.h"
224ce89b 27#include "include/stringify.h"
7c673cae
FG
28#include "rgw_common.h"
29#include "rgw_rados.h"
30#include "rgw_user.h"
31#include "rgw_period_pusher.h"
32#include "rgw_realm_reloader.h"
33#include "rgw_rest.h"
34#include "rgw_rest_s3.h"
35#include "rgw_rest_swift.h"
36#include "rgw_rest_admin.h"
37#include "rgw_rest_usage.h"
38#include "rgw_rest_user.h"
39#include "rgw_rest_bucket.h"
40#include "rgw_rest_metadata.h"
41#include "rgw_rest_log.h"
42#include "rgw_rest_opstate.h"
43#include "rgw_replica_log.h"
44#include "rgw_rest_replica_log.h"
45#include "rgw_rest_config.h"
46#include "rgw_rest_realm.h"
47#include "rgw_swift_auth.h"
48#include "rgw_log.h"
49#include "rgw_tools.h"
50#include "rgw_resolve.h"
51
52#include "rgw_request.h"
53#include "rgw_process.h"
54#include "rgw_frontend.h"
94b18763 55#include "rgw_http_client_curl.h"
7c673cae
FG
56#if defined(WITH_RADOSGW_BEAST_FRONTEND)
57#include "rgw_asio_frontend.h"
58#endif /* WITH_RADOSGW_BEAST_FRONTEND */
59
60#include <map>
61#include <string>
62#include <vector>
63#include <atomic>
64
65#include "include/types.h"
66#include "common/BackTrace.h"
67
68#ifdef HAVE_SYS_PRCTL_H
69#include <sys/prctl.h>
70#endif
71
72#define dout_subsys ceph_subsys_rgw
73
74using namespace std;
75
76static sig_t sighandler_alrm;
77
78class RGWProcess;
79
80static int signal_fd[2] = {0, 0};
81static std::atomic<int64_t> disable_signal_fd = { 0 };
82
83void signal_shutdown()
84{
85 if (!disable_signal_fd) {
86 int val = 0;
87 int ret = write(signal_fd[0], (char *)&val, sizeof(val));
88 if (ret < 0) {
89 derr << "ERROR: " << __func__ << ": write() returned "
90 << cpp_strerror(errno) << dendl;
91 }
92 }
93}
94
95static void wait_shutdown()
96{
97 int val;
98 int r = safe_read_exact(signal_fd[1], &val, sizeof(val));
99 if (r < 0) {
100 derr << "safe_read_exact returned with error" << dendl;
101 }
102}
103
104static int signal_fd_init()
105{
106 return socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fd);
107}
108
109static void signal_fd_finalize()
110{
111 close(signal_fd[0]);
112 close(signal_fd[1]);
113}
114
115static void handle_sigterm(int signum)
116{
117 dout(1) << __func__ << dendl;
118#if defined(WITH_RADOSGW_FCGI_FRONTEND)
119 FCGX_ShutdownPending();
120#endif
121
122 // send a signal to make fcgi's accept(2) wake up. unfortunately the
123 // initial signal often isn't sufficient because we race with accept's
124 // check of the flag wet by ShutdownPending() above.
125 if (signum != SIGUSR1) {
126 signal_shutdown();
127
128 // safety net in case we get stuck doing an orderly shutdown.
129 uint64_t secs = g_ceph_context->_conf->rgw_exit_timeout_secs;
130 if (secs)
131 alarm(secs);
132 dout(1) << __func__ << " set alarm for " << secs << dendl;
133 }
134
135}
136
137static void godown_alarm(int signum)
138{
139 _exit(0);
140}
141
7c673cae
FG
142
143class C_InitTimeout : public Context {
144public:
145 C_InitTimeout() {}
146 void finish(int r) override {
147 derr << "Initialization timeout, failed to initialize" << dendl;
148 exit(1);
149 }
150};
151
152static int usage()
153{
154 cerr << "usage: radosgw [options...]" << std::endl;
155 cerr << "options:\n";
156 cerr << " --rgw-region=<region> region in which radosgw runs\n";
157 cerr << " --rgw-zone=<zone> zone in which radosgw runs\n";
158 cerr << " --rgw-socket-path=<path> specify a unix domain socket path\n";
159 cerr << " -m monaddress[:port] connect to specified monitor\n";
160 cerr << " --keyring=<path> path to radosgw keyring\n";
161 cerr << " --logfile=<logfile> file to log debug output\n";
162 cerr << " --debug-rgw=<log-level>/<memory-level> set radosgw debug level\n";
163 generic_server_usage();
164
165 return 0;
166}
167
168static RGWRESTMgr *set_logging(RGWRESTMgr *mgr)
169{
170 mgr->set_logging(true);
171 return mgr;
172}
173
31f18b77
FG
174static RGWRESTMgr *rest_filter(RGWRados *store, int dialect, RGWRESTMgr *orig)
175{
176 RGWSyncModuleInstanceRef sync_module = store->get_sync_module();
94b18763
FG
177 if (sync_module) {
178 return sync_module->get_rest_filter(dialect, orig);
179 } else {
180 return orig;
181 }
31f18b77
FG
182}
183
7c673cae
FG
184/*
185 * start up the RADOS connection and then handle HTTP messages as they come in
186 */
7c673cae 187int main(int argc, const char **argv)
7c673cae
FG
188{
189 // dout() messages will be sent to stderr, but FCGX wants messages on stdout
190 // Redirect stderr to stdout.
191 TEMP_FAILURE_RETRY(close(STDERR_FILENO));
192 if (TEMP_FAILURE_RETRY(dup2(STDOUT_FILENO, STDERR_FILENO)) < 0) {
193 int err = errno;
194 cout << "failed to redirect stderr to stdout: " << cpp_strerror(err)
195 << std::endl;
196 return ENOSYS;
197 }
198
199 /* alternative default for module */
200 vector<const char *> def_args;
201 def_args.push_back("--debug-rgw=1/5");
202 def_args.push_back("--keyring=$rgw_data/keyring");
91327a77 203 def_args.push_back("--objecter_inflight_ops=24576");
7c673cae
FG
204
205 vector<const char*> args;
206 argv_to_vec(argc, argv, args);
207 env_to_vec(args);
208
209 // First, let's determine which frontends are configured.
210 int flags = CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS;
211 global_pre_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_DAEMON,
212 flags);
213
214 list<string> frontends;
215 get_str_list(g_conf->rgw_frontends, ",", frontends);
216 multimap<string, RGWFrontendConfig *> fe_map;
217 list<RGWFrontendConfig *> configs;
218 if (frontends.empty()) {
31f18b77 219 frontends.push_back("civetweb");
7c673cae
FG
220 }
221 for (list<string>::iterator iter = frontends.begin(); iter != frontends.end(); ++iter) {
222 string& f = *iter;
223
91327a77
AA
224 if (f.find("civetweb") != string::npos || f.find("beast") != string::npos) {
225 // If civetweb or beast is configured as a frontend, prevent global_init() from
7c673cae
FG
226 // dropping permissions by setting the appropriate flag.
227 flags |= CINIT_FLAG_DEFER_DROP_PRIVILEGES;
228 if (f.find("port") != string::npos) {
229 // check for the most common ws problems
230 if ((f.find("port=") == string::npos) ||
231 (f.find("port= ") != string::npos)) {
91327a77
AA
232 derr << "WARNING: radosgw frontend config found unexpected spacing around 'port' "
233 << "(ensure frontend port parameter has the form 'port=80' with no spaces "
7c673cae
FG
234 << "before or after '=')" << dendl;
235 }
236 }
237 }
238
239 RGWFrontendConfig *config = new RGWFrontendConfig(f);
240 int r = config->init();
241 if (r < 0) {
242 delete config;
243 cerr << "ERROR: failed to init config: " << f << std::endl;
244 return EINVAL;
245 }
246
247 configs.push_back(config);
248
249 string framework = config->get_framework();
250 fe_map.insert(pair<string, RGWFrontendConfig*>(framework, config));
251 }
252
253 // Now that we've determined which frontend(s) to use, continue with global
254 // initialization. Passing false as the final argument ensures that
255 // global_pre_init() is not invoked twice.
256 // claim the reference and release it after subsequent destructors have fired
257 auto cct = global_init(&def_args, args, CEPH_ENTITY_TYPE_CLIENT,
258 CODE_ENVIRONMENT_DAEMON,
259 flags, "rgw_data", false);
260
261 for (std::vector<const char*>::iterator i = args.begin(); i != args.end(); ++i) {
262 if (ceph_argparse_flag(args, i, "-h", "--help", (char*)NULL)) {
263 usage();
264 return 0;
265 }
266 }
267
268 // maintain existing region root pool for new multisite objects
269 if (!g_conf->rgw_region_root_pool.empty()) {
270 const char *root_pool = g_conf->rgw_region_root_pool.c_str();
271 if (g_conf->rgw_zonegroup_root_pool.empty()) {
272 g_conf->set_val_or_die("rgw_zonegroup_root_pool", root_pool);
273 }
274 if (g_conf->rgw_period_root_pool.empty()) {
275 g_conf->set_val_or_die("rgw_period_root_pool", root_pool);
276 }
277 if (g_conf->rgw_realm_root_pool.empty()) {
278 g_conf->set_val_or_die("rgw_realm_root_pool", root_pool);
279 }
280 }
281
282 // for region -> zonegroup conversion (must happen before common_init_finish())
283 if (!g_conf->rgw_region.empty() && g_conf->rgw_zonegroup.empty()) {
284 g_conf->set_val_or_die("rgw_zonegroup", g_conf->rgw_region.c_str());
285 }
286
7c673cae
FG
287 if (g_conf->daemonize) {
288 global_init_daemonize(g_ceph_context);
289 }
290 Mutex mutex("main");
291 SafeTimer init_timer(g_ceph_context, mutex);
292 init_timer.init();
293 mutex.Lock();
294 init_timer.add_event_after(g_conf->rgw_init_timeout, new C_InitTimeout);
295 mutex.Unlock();
296
297 // Enable the perf counter before starting the service thread
298 g_ceph_context->enable_perf_counter();
299
300 common_init_finish(g_ceph_context);
301
302 int r = rgw_tools_init(g_ceph_context);
303 if (r < 0) {
304 derr << "ERROR: unable to initialize rgw tools" << dendl;
305 return -r;
306 }
307
308 rgw_init_resolver();
94b18763
FG
309 rgw::curl::setup_curl(fe_map);
310
7c673cae
FG
311#if defined(WITH_RADOSGW_FCGI_FRONTEND)
312 FCGX_Init();
313#endif
314
315 RGWRados *store = RGWStoreManager::get_storage(g_ceph_context,
316 g_conf->rgw_enable_gc_threads, g_conf->rgw_enable_lc_threads, g_conf->rgw_enable_quota_threads,
28e407b8 317 g_conf->rgw_run_sync_thread, g_conf->rgw_dynamic_resharding, g_conf->rgw_cache_enabled);
7c673cae
FG
318 if (!store) {
319 mutex.Lock();
320 init_timer.cancel_all_events();
321 init_timer.shutdown();
322 mutex.Unlock();
323
324 derr << "Couldn't init storage provider (RADOS)" << dendl;
325 return EIO;
326 }
327 r = rgw_perf_start(g_ceph_context);
328 if (r < 0) {
329 derr << "ERROR: failed starting rgw perf" << dendl;
330 return -r;
331 }
332
333 rgw_rest_init(g_ceph_context, store, store->get_zonegroup());
334
335 mutex.Lock();
336 init_timer.cancel_all_events();
337 init_timer.shutdown();
338 mutex.Unlock();
339
340 rgw_user_init(store);
341 rgw_bucket_init(store->meta_mgr);
342 rgw_log_usage_init(g_ceph_context, store);
343
344 RGWREST rest;
345
346 list<string> apis;
347
348 get_str_list(g_conf->rgw_enable_apis, apis);
349
350 map<string, bool> apis_map;
351 for (list<string>::iterator li = apis.begin(); li != apis.end(); ++li) {
352 apis_map[*li] = true;
353 }
354
355 // S3 website mode is a specialization of S3
356 const bool s3website_enabled = apis_map.count("s3website") > 0;
357 // Swift API entrypoint could placed in the root instead of S3
358 const bool swift_at_root = g_conf->rgw_swift_url_prefix == "/";
359 if (apis_map.count("s3") > 0 || s3website_enabled) {
360 if (! swift_at_root) {
31f18b77
FG
361 rest.register_default_mgr(set_logging(rest_filter(store, RGW_REST_S3,
362 new RGWRESTMgr_S3(s3website_enabled))));
7c673cae
FG
363 } else {
364 derr << "Cannot have the S3 or S3 Website enabled together with "
365 << "Swift API placed in the root of hierarchy" << dendl;
366 return EINVAL;
367 }
368 }
369
370 if (apis_map.count("swift") > 0) {
371 RGWRESTMgr_SWIFT* const swift_resource = new RGWRESTMgr_SWIFT;
372
373 if (! g_conf->rgw_cross_domain_policy.empty()) {
374 swift_resource->register_resource("crossdomain.xml",
375 set_logging(new RGWRESTMgr_SWIFT_CrossDomain));
376 }
377
378 swift_resource->register_resource("healthcheck",
379 set_logging(new RGWRESTMgr_SWIFT_HealthCheck));
380
381 swift_resource->register_resource("info",
382 set_logging(new RGWRESTMgr_SWIFT_Info));
383
384 if (! swift_at_root) {
385 rest.register_resource(g_conf->rgw_swift_url_prefix,
31f18b77
FG
386 set_logging(rest_filter(store, RGW_REST_SWIFT,
387 swift_resource)));
7c673cae
FG
388 } else {
389 if (store->get_zonegroup().zones.size() > 1) {
390 derr << "Placing Swift API in the root of URL hierarchy while running"
391 << " multi-site configuration requires another instance of RadosGW"
392 << " with S3 API enabled!" << dendl;
393 }
394
395 rest.register_default_mgr(set_logging(swift_resource));
396 }
397 }
398
399 if (apis_map.count("swift_auth") > 0) {
400 rest.register_resource(g_conf->rgw_swift_auth_entry,
401 set_logging(new RGWRESTMgr_SWIFT_Auth));
402 }
403
404 if (apis_map.count("admin") > 0) {
405 RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin;
406 admin_resource->register_resource("usage", new RGWRESTMgr_Usage);
407 admin_resource->register_resource("user", new RGWRESTMgr_User);
408 admin_resource->register_resource("bucket", new RGWRESTMgr_Bucket);
409
410 /*Registering resource for /admin/metadata */
411 admin_resource->register_resource("metadata", new RGWRESTMgr_Metadata);
412 admin_resource->register_resource("log", new RGWRESTMgr_Log);
413 admin_resource->register_resource("opstate", new RGWRESTMgr_Opstate);
414 admin_resource->register_resource("replica_log", new RGWRESTMgr_ReplicaLog);
415 admin_resource->register_resource("config", new RGWRESTMgr_Config);
416 admin_resource->register_resource("realm", new RGWRESTMgr_Realm);
417 rest.register_resource(g_conf->rgw_admin_entry, admin_resource);
418 }
419
420 /* Initialize the registry of auth strategies which will coordinate
421 * the dynamic reconfiguration. */
28e407b8
AA
422 rgw::auth::ImplicitTenants implicit_tenant_context{*g_conf};
423 g_conf->add_observer(&implicit_tenant_context);
7c673cae 424 auto auth_registry = \
28e407b8 425 rgw::auth::StrategyRegistry::create(g_ceph_context, implicit_tenant_context, store);
7c673cae
FG
426
427 /* Header custom behavior */
428 rest.register_x_headers(g_conf->rgw_log_http_headers);
429
430 OpsLogSocket *olog = NULL;
431
432 if (!g_conf->rgw_ops_log_socket_path.empty()) {
433 olog = new OpsLogSocket(g_ceph_context, g_conf->rgw_ops_log_data_backlog);
434 olog->init(g_conf->rgw_ops_log_socket_path);
435 }
436
437 r = signal_fd_init();
438 if (r < 0) {
439 derr << "ERROR: unable to initialize signal fds" << dendl;
440 exit(1);
441 }
442
443 init_async_signal_handler();
b32b8144 444 register_async_signal_handler(SIGHUP, sighup_handler);
7c673cae
FG
445 register_async_signal_handler(SIGTERM, handle_sigterm);
446 register_async_signal_handler(SIGINT, handle_sigterm);
447 register_async_signal_handler(SIGUSR1, handle_sigterm);
448 sighandler_alrm = signal(SIGALRM, godown_alarm);
449
224ce89b
WB
450 map<string, string> service_map_meta;
451 service_map_meta["pid"] = stringify(getpid());
452
7c673cae
FG
453 list<RGWFrontend *> fes;
454
224ce89b
WB
455 int fe_count = 0;
456
7c673cae 457 for (multimap<string, RGWFrontendConfig *>::iterator fiter = fe_map.begin();
224ce89b 458 fiter != fe_map.end(); ++fiter, ++fe_count) {
7c673cae
FG
459 RGWFrontendConfig *config = fiter->second;
460 string framework = config->get_framework();
461 RGWFrontend *fe = NULL;
462
463 if (framework == "civetweb" || framework == "mongoose") {
224ce89b 464 framework = "civetweb";
7c673cae
FG
465 std::string uri_prefix;
466 config->get_val("prefix", "", &uri_prefix);
467
468 RGWProcessEnv env = { store, &rest, olog, 0, uri_prefix, auth_registry };
469
470 fe = new RGWCivetWebFrontend(env, config);
471 }
472 else if (framework == "loadgen") {
473 int port;
474 config->get_val("port", 80, &port);
475 std::string uri_prefix;
476 config->get_val("prefix", "", &uri_prefix);
477
478 RGWProcessEnv env = { store, &rest, olog, port, uri_prefix, auth_registry };
479
480 fe = new RGWLoadGenFrontend(env, config);
481 }
482#if defined(WITH_RADOSGW_BEAST_FRONTEND)
483 else if ((framework == "beast") &&
484 cct->check_experimental_feature_enabled("rgw-beast-frontend")) {
485 int port;
486 config->get_val("port", 80, &port);
487 std::string uri_prefix;
488 config->get_val("prefix", "", &uri_prefix);
489 RGWProcessEnv env{ store, &rest, olog, port, uri_prefix, auth_registry };
94b18763 490 fe = new RGWAsioFrontend(env, config);
7c673cae
FG
491 }
492#endif /* WITH_RADOSGW_BEAST_FRONTEND */
493#if defined(WITH_RADOSGW_FCGI_FRONTEND)
494 else if (framework == "fastcgi" || framework == "fcgi") {
224ce89b 495 framework = "fastcgi";
7c673cae
FG
496 std::string uri_prefix;
497 config->get_val("prefix", "", &uri_prefix);
498 RGWProcessEnv fcgi_pe = { store, &rest, olog, 0, uri_prefix, auth_registry };
499
500 fe = new RGWFCGXFrontend(fcgi_pe, config);
501 }
502#endif /* WITH_RADOSGW_FCGI_FRONTEND */
503
224ce89b
WB
504 service_map_meta["frontend_type#" + stringify(fe_count)] = framework;
505 service_map_meta["frontend_config#" + stringify(fe_count)] = config->get_config();
506
7c673cae
FG
507 if (fe == NULL) {
508 dout(0) << "WARNING: skipping unknown framework: " << framework << dendl;
509 continue;
510 }
511
512 dout(0) << "starting handler: " << fiter->first << dendl;
513 int r = fe->init();
514 if (r < 0) {
515 derr << "ERROR: failed initializing frontend" << dendl;
516 return -r;
517 }
518 r = fe->run();
519 if (r < 0) {
520 derr << "ERROR: failed run" << dendl;
521 return -r;
522 }
523
524 fes.push_back(fe);
525 }
526
224ce89b
WB
527 r = store->register_to_service_map("rgw", service_map_meta);
528 if (r < 0) {
529 derr << "ERROR: failed to register to service map: " << cpp_strerror(-r) << dendl;
530
531 /* ignore error */
532 }
533
534
7c673cae
FG
535 // add a watcher to respond to realm configuration changes
536 RGWPeriodPusher pusher(store);
28e407b8 537 RGWFrontendPauser pauser(fes, implicit_tenant_context, &pusher);
224ce89b 538 RGWRealmReloader reloader(store, service_map_meta, &pauser);
7c673cae 539
7c673cae
FG
540 RGWRealmWatcher realm_watcher(g_ceph_context, store->realm);
541 realm_watcher.add_watcher(RGWRealmNotify::Reload, reloader);
542 realm_watcher.add_watcher(RGWRealmNotify::ZonesNeedPeriod, pusher);
543
544#if defined(HAVE_SYS_PRCTL_H)
545 if (prctl(PR_SET_DUMPABLE, 1) == -1) {
546 cerr << "warning: unable to set dumpable flag: " << cpp_strerror(errno) << std::endl;
547 }
548#endif
549
550 wait_shutdown();
551
552 derr << "shutting down" << dendl;
553
554 for (list<RGWFrontend *>::iterator liter = fes.begin(); liter != fes.end();
555 ++liter) {
556 RGWFrontend *fe = *liter;
557 fe->stop();
558 }
559
560 for (list<RGWFrontend *>::iterator liter = fes.begin(); liter != fes.end();
561 ++liter) {
562 RGWFrontend *fe = *liter;
563 fe->join();
564 delete fe;
565 }
566
567 for (list<RGWFrontendConfig *>::iterator liter = configs.begin();
568 liter != configs.end(); ++liter) {
569 RGWFrontendConfig *fec = *liter;
570 delete fec;
571 }
572
b32b8144 573 unregister_async_signal_handler(SIGHUP, sighup_handler);
7c673cae
FG
574 unregister_async_signal_handler(SIGTERM, handle_sigterm);
575 unregister_async_signal_handler(SIGINT, handle_sigterm);
576 unregister_async_signal_handler(SIGUSR1, handle_sigterm);
577 shutdown_async_signal_handler();
578
579 rgw_log_usage_finalize();
580
581 delete olog;
582
583 RGWStoreManager::close_storage(store);
584
585 rgw_tools_cleanup();
586 rgw_shutdown_resolver();
94b18763 587 rgw::curl::cleanup_curl();
28e407b8 588 g_conf->remove_observer(&implicit_tenant_context);
7c673cae
FG
589
590 rgw_perf_stop(g_ceph_context);
591
592 dout(1) << "final shutdown" << dendl;
593
594 signal_fd_finalize();
595
596 return 0;
597}