]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_main.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / rgw / rgw_main.cc
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae 3
f67539c2 4#include <boost/intrusive/list.hpp>
7c673cae
FG
5#include "common/ceph_argparse.h"
6#include "global/global_init.h"
7#include "global/signal_handler.h"
8#include "common/config.h"
9#include "common/errno.h"
10#include "common/Timer.h"
11#include "common/safe_io.h"
11fdf7f2 12#include "common/TracepointProvider.h"
f67539c2 13#include "common/openssl_opts_handler.h"
9f95a23c 14#include "common/numa.h"
7c673cae
FG
15#include "include/compat.h"
16#include "include/str_list.h"
224ce89b 17#include "include/stringify.h"
7c673cae 18#include "rgw_common.h"
f67539c2 19#include "rgw_sal.h"
7c673cae
FG
20#include "rgw_period_pusher.h"
21#include "rgw_realm_reloader.h"
22#include "rgw_rest.h"
23#include "rgw_rest_s3.h"
24#include "rgw_rest_swift.h"
25#include "rgw_rest_admin.h"
26#include "rgw_rest_usage.h"
27#include "rgw_rest_user.h"
28#include "rgw_rest_bucket.h"
29#include "rgw_rest_metadata.h"
30#include "rgw_rest_log.h"
7c673cae
FG
31#include "rgw_rest_config.h"
32#include "rgw_rest_realm.h"
11fdf7f2 33#include "rgw_rest_sts.h"
7c673cae
FG
34#include "rgw_swift_auth.h"
35#include "rgw_log.h"
36#include "rgw_tools.h"
37#include "rgw_resolve.h"
7c673cae
FG
38#include "rgw_request.h"
39#include "rgw_process.h"
40#include "rgw_frontend.h"
94b18763 41#include "rgw_http_client_curl.h"
f67539c2
TL
42#include "rgw_kmip_client.h"
43#include "rgw_kmip_client_impl.h"
11fdf7f2 44#include "rgw_perf_counters.h"
eafe8130
TL
45#ifdef WITH_RADOSGW_AMQP_ENDPOINT
46#include "rgw_amqp.h"
47#endif
9f95a23c
TL
48#ifdef WITH_RADOSGW_KAFKA_ENDPOINT
49#include "rgw_kafka.h"
50#endif
7c673cae
FG
51#if defined(WITH_RADOSGW_BEAST_FRONTEND)
52#include "rgw_asio_frontend.h"
53#endif /* WITH_RADOSGW_BEAST_FRONTEND */
11fdf7f2 54#include "rgw_dmclock_scheduler_ctx.h"
f67539c2
TL
55#ifdef WITH_RADOSGW_LUA_PACKAGES
56#include "rgw_lua.h"
57#endif
7c673cae 58
11fdf7f2 59#include "services/svc_zone.h"
7c673cae
FG
60
61#ifdef HAVE_SYS_PRCTL_H
62#include <sys/prctl.h>
63#endif
64
65#define dout_subsys ceph_subsys_rgw
66
11fdf7f2
TL
67namespace {
68TracepointProvider::Traits rgw_op_tracepoint_traits("librgw_op_tp.so",
69 "rgw_op_tracing");
70TracepointProvider::Traits rgw_rados_tracepoint_traits("librgw_rados_tp.so",
71 "rgw_rados_tracing");
72}
7c673cae
FG
73
74static sig_t sighandler_alrm;
75
76class RGWProcess;
77
78static int signal_fd[2] = {0, 0};
7c673cae
FG
79
80void signal_shutdown()
81{
11fdf7f2
TL
82 int val = 0;
83 int ret = write(signal_fd[0], (char *)&val, sizeof(val));
84 if (ret < 0) {
85 derr << "ERROR: " << __func__ << ": write() returned "
86 << cpp_strerror(errno) << dendl;
7c673cae
FG
87 }
88}
89
90static void wait_shutdown()
91{
92 int val;
93 int r = safe_read_exact(signal_fd[1], &val, sizeof(val));
94 if (r < 0) {
95 derr << "safe_read_exact returned with error" << dendl;
96 }
97}
98
99static int signal_fd_init()
100{
101 return socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fd);
102}
103
104static void signal_fd_finalize()
105{
106 close(signal_fd[0]);
107 close(signal_fd[1]);
108}
109
110static void handle_sigterm(int signum)
111{
112 dout(1) << __func__ << dendl;
113#if defined(WITH_RADOSGW_FCGI_FRONTEND)
114 FCGX_ShutdownPending();
115#endif
116
117 // send a signal to make fcgi's accept(2) wake up. unfortunately the
118 // initial signal often isn't sufficient because we race with accept's
119 // check of the flag wet by ShutdownPending() above.
120 if (signum != SIGUSR1) {
121 signal_shutdown();
122
123 // safety net in case we get stuck doing an orderly shutdown.
124 uint64_t secs = g_ceph_context->_conf->rgw_exit_timeout_secs;
125 if (secs)
126 alarm(secs);
127 dout(1) << __func__ << " set alarm for " << secs << dendl;
128 }
129
130}
131
132static void godown_alarm(int signum)
133{
134 _exit(0);
135}
136
7c673cae
FG
137
138class C_InitTimeout : public Context {
139public:
140 C_InitTimeout() {}
141 void finish(int r) override {
142 derr << "Initialization timeout, failed to initialize" << dendl;
143 exit(1);
144 }
145};
146
147static int usage()
148{
11fdf7f2
TL
149 cout << "usage: radosgw [options...]" << std::endl;
150 cout << "options:\n";
151 cout << " --rgw-region=<region> region in which radosgw runs\n";
152 cout << " --rgw-zone=<zone> zone in which radosgw runs\n";
153 cout << " --rgw-socket-path=<path> specify a unix domain socket path\n";
154 cout << " -m monaddress[:port] connect to specified monitor\n";
155 cout << " --keyring=<path> path to radosgw keyring\n";
156 cout << " --logfile=<logfile> file to log debug output\n";
157 cout << " --debug-rgw=<log-level>/<memory-level> set radosgw debug level\n";
7c673cae
FG
158 generic_server_usage();
159
160 return 0;
161}
162
163static RGWRESTMgr *set_logging(RGWRESTMgr *mgr)
164{
165 mgr->set_logging(true);
166 return mgr;
167}
168
31f18b77
FG
169static RGWRESTMgr *rest_filter(RGWRados *store, int dialect, RGWRESTMgr *orig)
170{
171 RGWSyncModuleInstanceRef sync_module = store->get_sync_module();
94b18763
FG
172 if (sync_module) {
173 return sync_module->get_rest_filter(dialect, orig);
174 } else {
175 return orig;
176 }
31f18b77
FG
177}
178
7c673cae
FG
179/*
180 * start up the RADOS connection and then handle HTTP messages as they come in
181 */
9f95a23c 182int radosgw_Main(int argc, const char **argv)
7c673cae
FG
183{
184 // dout() messages will be sent to stderr, but FCGX wants messages on stdout
185 // Redirect stderr to stdout.
186 TEMP_FAILURE_RETRY(close(STDERR_FILENO));
187 if (TEMP_FAILURE_RETRY(dup2(STDOUT_FILENO, STDERR_FILENO)) < 0) {
188 int err = errno;
189 cout << "failed to redirect stderr to stdout: " << cpp_strerror(err)
190 << std::endl;
191 return ENOSYS;
192 }
193
194 /* alternative default for module */
11fdf7f2
TL
195 map<string,string> defaults = {
196 { "debug_rgw", "1/5" },
197 { "keyring", "$rgw_data/keyring" },
198 { "objecter_inflight_ops", "24576" }
199 };
7c673cae
FG
200
201 vector<const char*> args;
202 argv_to_vec(argc, argv, args);
11fdf7f2
TL
203 if (args.empty()) {
204 cerr << argv[0] << ": -h or --help for usage" << std::endl;
205 exit(1);
206 }
207 if (ceph_argparse_need_usage(args)) {
208 usage();
209 exit(0);
210 }
7c673cae 211
7c673cae 212 int flags = CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS;
1911f103
TL
213 // Prevent global_init() from dropping permissions until frontends can bind
214 // privileged ports
215 flags |= CINIT_FLAG_DEFER_DROP_PRIVILEGES;
216
9f95a23c 217 auto cct = global_init(&defaults, args, CEPH_ENTITY_TYPE_CLIENT,
f67539c2 218 CODE_ENVIRONMENT_DAEMON, flags);
9f95a23c
TL
219
220 // First, let's determine which frontends are configured.
7c673cae 221 list<string> frontends;
9f95a23c
TL
222 string rgw_frontends_str = g_conf().get_val<string>("rgw_frontends");
223 g_conf().early_expand_meta(rgw_frontends_str, &cerr);
224 get_str_list(rgw_frontends_str, ",", frontends);
7c673cae
FG
225 multimap<string, RGWFrontendConfig *> fe_map;
226 list<RGWFrontendConfig *> configs;
227 if (frontends.empty()) {
31f18b77 228 frontends.push_back("civetweb");
7c673cae
FG
229 }
230 for (list<string>::iterator iter = frontends.begin(); iter != frontends.end(); ++iter) {
231 string& f = *iter;
232
91327a77 233 if (f.find("civetweb") != string::npos || f.find("beast") != string::npos) {
7c673cae
FG
234 if (f.find("port") != string::npos) {
235 // check for the most common ws problems
236 if ((f.find("port=") == string::npos) ||
237 (f.find("port= ") != string::npos)) {
91327a77
AA
238 derr << "WARNING: radosgw frontend config found unexpected spacing around 'port' "
239 << "(ensure frontend port parameter has the form 'port=80' with no spaces "
7c673cae
FG
240 << "before or after '=')" << dendl;
241 }
242 }
243 }
244
245 RGWFrontendConfig *config = new RGWFrontendConfig(f);
246 int r = config->init();
247 if (r < 0) {
248 delete config;
249 cerr << "ERROR: failed to init config: " << f << std::endl;
250 return EINVAL;
251 }
252
253 configs.push_back(config);
254
255 string framework = config->get_framework();
256 fe_map.insert(pair<string, RGWFrontendConfig*>(framework, config));
257 }
258
9f95a23c
TL
259 int numa_node = g_conf().get_val<int64_t>("rgw_numa_node");
260 size_t numa_cpu_set_size = 0;
261 cpu_set_t numa_cpu_set;
262
263 if (numa_node >= 0) {
264 int r = get_numa_node_cpu_set(numa_node, &numa_cpu_set_size, &numa_cpu_set);
265 if (r < 0) {
266 dout(1) << __func__ << " unable to determine rgw numa node " << numa_node
267 << " CPUs" << dendl;
268 numa_node = -1;
269 } else {
270 r = set_cpu_affinity_all_threads(numa_cpu_set_size, &numa_cpu_set);
271 if (r < 0) {
272 derr << __func__ << " failed to set numa affinity: " << cpp_strerror(r)
273 << dendl;
274 }
275 }
276 } else {
277 dout(1) << __func__ << " not setting numa affinity" << dendl;
278 }
7c673cae 279
7c673cae 280 // maintain existing region root pool for new multisite objects
11fdf7f2
TL
281 if (!g_conf()->rgw_region_root_pool.empty()) {
282 const char *root_pool = g_conf()->rgw_region_root_pool.c_str();
283 if (g_conf()->rgw_zonegroup_root_pool.empty()) {
284 g_conf().set_val_or_die("rgw_zonegroup_root_pool", root_pool);
7c673cae 285 }
11fdf7f2
TL
286 if (g_conf()->rgw_period_root_pool.empty()) {
287 g_conf().set_val_or_die("rgw_period_root_pool", root_pool);
7c673cae 288 }
11fdf7f2
TL
289 if (g_conf()->rgw_realm_root_pool.empty()) {
290 g_conf().set_val_or_die("rgw_realm_root_pool", root_pool);
7c673cae
FG
291 }
292 }
293
294 // for region -> zonegroup conversion (must happen before common_init_finish())
11fdf7f2
TL
295 if (!g_conf()->rgw_region.empty() && g_conf()->rgw_zonegroup.empty()) {
296 g_conf().set_val_or_die("rgw_zonegroup", g_conf()->rgw_region.c_str());
7c673cae
FG
297 }
298
11fdf7f2 299 if (g_conf()->daemonize) {
7c673cae
FG
300 global_init_daemonize(g_ceph_context);
301 }
9f95a23c 302 ceph::mutex mutex = ceph::make_mutex("main");
7c673cae
FG
303 SafeTimer init_timer(g_ceph_context, mutex);
304 init_timer.init();
9f95a23c 305 mutex.lock();
11fdf7f2 306 init_timer.add_event_after(g_conf()->rgw_init_timeout, new C_InitTimeout);
9f95a23c 307 mutex.unlock();
7c673cae 308
f67539c2
TL
309 ceph::crypto::init_openssl_engine_once();
310
7c673cae
FG
311 common_init_finish(g_ceph_context);
312
11fdf7f2
TL
313 init_async_signal_handler();
314 register_async_signal_handler(SIGHUP, sighup_handler);
315
316 TracepointProvider::initialize<rgw_rados_tracepoint_traits>(g_ceph_context);
317 TracepointProvider::initialize<rgw_op_tracepoint_traits>(g_ceph_context);
318
7c673cae
FG
319 int r = rgw_tools_init(g_ceph_context);
320 if (r < 0) {
321 derr << "ERROR: unable to initialize rgw tools" << dendl;
322 return -r;
323 }
324
325 rgw_init_resolver();
94b18763 326 rgw::curl::setup_curl(fe_map);
11fdf7f2 327 rgw_http_client_init(g_ceph_context);
f67539c2 328 rgw_kmip_client_init(*new RGWKMIPManagerImpl(g_ceph_context));
11fdf7f2 329
7c673cae
FG
330#if defined(WITH_RADOSGW_FCGI_FRONTEND)
331 FCGX_Init();
332#endif
333
b3b6e05e 334 const DoutPrefix dp(cct.get(), dout_subsys, "rgw main: ");
9f95a23c 335 rgw::sal::RGWRadosStore *store =
b3b6e05e 336 RGWStoreManager::get_storage(&dp, g_ceph_context,
11fdf7f2
TL
337 g_conf()->rgw_enable_gc_threads,
338 g_conf()->rgw_enable_lc_threads,
339 g_conf()->rgw_enable_quota_threads,
340 g_conf()->rgw_run_sync_thread,
341 g_conf().get_val<bool>("rgw_dynamic_resharding"),
342 g_conf()->rgw_cache_enabled);
7c673cae 343 if (!store) {
9f95a23c 344 mutex.lock();
7c673cae
FG
345 init_timer.cancel_all_events();
346 init_timer.shutdown();
9f95a23c 347 mutex.unlock();
7c673cae
FG
348
349 derr << "Couldn't init storage provider (RADOS)" << dendl;
350 return EIO;
351 }
352 r = rgw_perf_start(g_ceph_context);
353 if (r < 0) {
354 derr << "ERROR: failed starting rgw perf" << dendl;
355 return -r;
356 }
357
9f95a23c 358 rgw_rest_init(g_ceph_context, store->svc()->zone->get_zonegroup());
7c673cae 359
9f95a23c 360 mutex.lock();
7c673cae
FG
361 init_timer.cancel_all_events();
362 init_timer.shutdown();
9f95a23c 363 mutex.unlock();
7c673cae 364
9f95a23c 365 rgw_log_usage_init(g_ceph_context, store->getRados());
7c673cae
FG
366
367 RGWREST rest;
368
369 list<string> apis;
370
11fdf7f2 371 get_str_list(g_conf()->rgw_enable_apis, apis);
7c673cae
FG
372
373 map<string, bool> apis_map;
374 for (list<string>::iterator li = apis.begin(); li != apis.end(); ++li) {
375 apis_map[*li] = true;
376 }
377
11fdf7f2
TL
378 /* warn about insecure keystone secret config options */
379 if (!(g_ceph_context->_conf->rgw_keystone_admin_token.empty() ||
380 g_ceph_context->_conf->rgw_keystone_admin_password.empty())) {
381 dout(0) << "WARNING: rgw_keystone_admin_token and rgw_keystone_admin_password should be avoided as they can expose secrets. Prefer the new rgw_keystone_admin_token_path and rgw_keystone_admin_password_path options, which read their secrets from files." << dendl;
382 }
383
7c673cae
FG
384 // S3 website mode is a specialization of S3
385 const bool s3website_enabled = apis_map.count("s3website") > 0;
11fdf7f2 386 const bool sts_enabled = apis_map.count("sts") > 0;
92f5a8d4 387 const bool iam_enabled = apis_map.count("iam") > 0;
f67539c2 388 const bool pubsub_enabled = apis_map.count("pubsub") > 0 || apis_map.count("notifications") > 0;
7c673cae 389 // Swift API entrypoint could placed in the root instead of S3
11fdf7f2 390 const bool swift_at_root = g_conf()->rgw_swift_url_prefix == "/";
7c673cae
FG
391 if (apis_map.count("s3") > 0 || s3website_enabled) {
392 if (! swift_at_root) {
9f95a23c 393 rest.register_default_mgr(set_logging(rest_filter(store->getRados(), RGW_REST_S3,
92f5a8d4 394 new RGWRESTMgr_S3(s3website_enabled, sts_enabled, iam_enabled, pubsub_enabled))));
7c673cae
FG
395 } else {
396 derr << "Cannot have the S3 or S3 Website enabled together with "
397 << "Swift API placed in the root of hierarchy" << dendl;
398 return EINVAL;
399 }
400 }
401
eafe8130
TL
402 if (pubsub_enabled) {
403#ifdef WITH_RADOSGW_AMQP_ENDPOINT
404 if (!rgw::amqp::init(cct.get())) {
405 dout(1) << "ERROR: failed to initialize AMQP manager" << dendl;
406 }
9f95a23c
TL
407#endif
408#ifdef WITH_RADOSGW_KAFKA_ENDPOINT
409 if (!rgw::kafka::init(cct.get())) {
410 dout(1) << "ERROR: failed to initialize Kafka manager" << dendl;
411 }
eafe8130
TL
412#endif
413 }
414
f67539c2
TL
415 const auto& luarocks_path = g_conf().get_val<std::string>("rgw_luarocks_location");
416 if (luarocks_path.empty()) {
417 store->set_luarocks_path("");
418 } else {
419 store->set_luarocks_path(luarocks_path+"/"+g_conf()->name.to_str());
420 }
421#ifdef WITH_RADOSGW_LUA_PACKAGES
422 rgw::lua::packages_t failed_packages;
423 std::string output;
b3b6e05e 424 r = rgw::lua::install_packages(&dp, store, null_yield, failed_packages, output);
f67539c2
TL
425 if (r < 0) {
426 dout(1) << "ERROR: failed to install lua packages from allowlist" << dendl;
427 }
428 if (!output.empty()) {
429 dout(10) << "INFO: lua packages installation output: \n" << output << dendl;
430 }
431 for (const auto& p : failed_packages) {
432 dout(5) << "WARNING: failed to install lua package: " << p << " from allowlist" << dendl;
433 }
434#endif
435
7c673cae
FG
436 if (apis_map.count("swift") > 0) {
437 RGWRESTMgr_SWIFT* const swift_resource = new RGWRESTMgr_SWIFT;
438
11fdf7f2 439 if (! g_conf()->rgw_cross_domain_policy.empty()) {
7c673cae
FG
440 swift_resource->register_resource("crossdomain.xml",
441 set_logging(new RGWRESTMgr_SWIFT_CrossDomain));
442 }
443
444 swift_resource->register_resource("healthcheck",
445 set_logging(new RGWRESTMgr_SWIFT_HealthCheck));
446
447 swift_resource->register_resource("info",
448 set_logging(new RGWRESTMgr_SWIFT_Info));
449
450 if (! swift_at_root) {
11fdf7f2 451 rest.register_resource(g_conf()->rgw_swift_url_prefix,
9f95a23c 452 set_logging(rest_filter(store->getRados(), RGW_REST_SWIFT,
31f18b77 453 swift_resource)));
7c673cae 454 } else {
9f95a23c 455 if (store->svc()->zone->get_zonegroup().zones.size() > 1) {
7c673cae
FG
456 derr << "Placing Swift API in the root of URL hierarchy while running"
457 << " multi-site configuration requires another instance of RadosGW"
458 << " with S3 API enabled!" << dendl;
459 }
460
461 rest.register_default_mgr(set_logging(swift_resource));
462 }
463 }
464
465 if (apis_map.count("swift_auth") > 0) {
11fdf7f2 466 rest.register_resource(g_conf()->rgw_swift_auth_entry,
7c673cae
FG
467 set_logging(new RGWRESTMgr_SWIFT_Auth));
468 }
469
470 if (apis_map.count("admin") > 0) {
471 RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin;
472 admin_resource->register_resource("usage", new RGWRESTMgr_Usage);
473 admin_resource->register_resource("user", new RGWRESTMgr_User);
474 admin_resource->register_resource("bucket", new RGWRESTMgr_Bucket);
475
476 /*Registering resource for /admin/metadata */
477 admin_resource->register_resource("metadata", new RGWRESTMgr_Metadata);
478 admin_resource->register_resource("log", new RGWRESTMgr_Log);
7c673cae
FG
479 admin_resource->register_resource("config", new RGWRESTMgr_Config);
480 admin_resource->register_resource("realm", new RGWRESTMgr_Realm);
11fdf7f2 481 rest.register_resource(g_conf()->rgw_admin_entry, admin_resource);
7c673cae
FG
482 }
483
484 /* Initialize the registry of auth strategies which will coordinate
485 * the dynamic reconfiguration. */
9f95a23c
TL
486 rgw::auth::ImplicitTenants implicit_tenant_context{g_conf()};
487 g_conf().add_observer(&implicit_tenant_context);
7c673cae 488 auto auth_registry = \
9f95a23c 489 rgw::auth::StrategyRegistry::create(g_ceph_context, implicit_tenant_context, store->getRados()->pctl);
7c673cae
FG
490
491 /* Header custom behavior */
11fdf7f2
TL
492 rest.register_x_headers(g_conf()->rgw_log_http_headers);
493
494 if (cct->_conf.get_val<std::string>("rgw_scheduler_type") == "dmclock" &&
495 !cct->check_experimental_feature_enabled("dmclock")){
496 derr << "dmclock scheduler type is experimental and needs to be"
497 << "set in the option enable experimental data corrupting features"
498 << dendl;
499 return EINVAL;
500 }
501
502 rgw::dmclock::SchedulerCtx sched_ctx{cct.get()};
7c673cae 503
a4b75251 504 OpsLogManifold *olog = new OpsLogManifold();
11fdf7f2 505 if (!g_conf()->rgw_ops_log_socket_path.empty()) {
a4b75251
TL
506 OpsLogSocket* olog_socket = new OpsLogSocket(g_ceph_context, g_conf()->rgw_ops_log_data_backlog);
507 olog_socket->init(g_conf()->rgw_ops_log_socket_path);
508 olog->add_sink(olog_socket);
509 }
510 OpsLogFile* ops_log_file;
511 if (!g_conf()->rgw_ops_log_file_path.empty()) {
512 ops_log_file = new OpsLogFile(g_ceph_context, g_conf()->rgw_ops_log_file_path, g_conf()->rgw_ops_log_data_backlog);
513 ops_log_file->start();
514 olog->add_sink(ops_log_file);
7c673cae 515 }
a4b75251 516 olog->add_sink(new OpsLogRados(store->getRados()));
7c673cae
FG
517
518 r = signal_fd_init();
519 if (r < 0) {
520 derr << "ERROR: unable to initialize signal fds" << dendl;
521 exit(1);
522 }
523
7c673cae
FG
524 register_async_signal_handler(SIGTERM, handle_sigterm);
525 register_async_signal_handler(SIGINT, handle_sigterm);
526 register_async_signal_handler(SIGUSR1, handle_sigterm);
527 sighandler_alrm = signal(SIGALRM, godown_alarm);
528
224ce89b
WB
529 map<string, string> service_map_meta;
530 service_map_meta["pid"] = stringify(getpid());
531
7c673cae
FG
532 list<RGWFrontend *> fes;
533
9f95a23c
TL
534 string frontend_defs_str = g_conf().get_val<string>("rgw_frontend_defaults");
535
536 list<string> frontends_def;
537 get_str_list(frontend_defs_str, ",", frontends_def);
538
539 map<string, std::unique_ptr<RGWFrontendConfig> > fe_def_map;
540 for (auto& f : frontends_def) {
541 RGWFrontendConfig *config = new RGWFrontendConfig(f);
542 int r = config->init();
543 if (r < 0) {
544 delete config;
545 cerr << "ERROR: failed to init default config: " << f << std::endl;
546 return EINVAL;
547 }
548
549 fe_def_map[config->get_framework()].reset(config);
550 }
551
224ce89b
WB
552 int fe_count = 0;
553
7c673cae 554 for (multimap<string, RGWFrontendConfig *>::iterator fiter = fe_map.begin();
224ce89b 555 fiter != fe_map.end(); ++fiter, ++fe_count) {
7c673cae
FG
556 RGWFrontendConfig *config = fiter->second;
557 string framework = config->get_framework();
9f95a23c
TL
558
559 auto def_iter = fe_def_map.find(framework);
560 if (def_iter != fe_def_map.end()) {
561 config->set_default_config(*def_iter->second);
562 }
563
7c673cae
FG
564 RGWFrontend *fe = NULL;
565
566 if (framework == "civetweb" || framework == "mongoose") {
522d829b
TL
567 lderr(cct.get()) << "IMPORTANT: the civetweb frontend is now deprecated "
568 "and will be removed in a future release" << dendl;
224ce89b 569 framework = "civetweb";
7c673cae
FG
570 std::string uri_prefix;
571 config->get_val("prefix", "", &uri_prefix);
572
573 RGWProcessEnv env = { store, &rest, olog, 0, uri_prefix, auth_registry };
11fdf7f2 574 //TODO: move all of scheduler initializations to frontends?
7c673cae 575
11fdf7f2 576 fe = new RGWCivetWebFrontend(env, config, sched_ctx);
7c673cae
FG
577 }
578 else if (framework == "loadgen") {
579 int port;
580 config->get_val("port", 80, &port);
581 std::string uri_prefix;
582 config->get_val("prefix", "", &uri_prefix);
583
584 RGWProcessEnv env = { store, &rest, olog, port, uri_prefix, auth_registry };
585
586 fe = new RGWLoadGenFrontend(env, config);
587 }
588#if defined(WITH_RADOSGW_BEAST_FRONTEND)
11fdf7f2 589 else if (framework == "beast") {
7c673cae
FG
590 int port;
591 config->get_val("port", 80, &port);
592 std::string uri_prefix;
593 config->get_val("prefix", "", &uri_prefix);
594 RGWProcessEnv env{ store, &rest, olog, port, uri_prefix, auth_registry };
11fdf7f2 595 fe = new RGWAsioFrontend(env, config, sched_ctx);
7c673cae
FG
596 }
597#endif /* WITH_RADOSGW_BEAST_FRONTEND */
598#if defined(WITH_RADOSGW_FCGI_FRONTEND)
599 else if (framework == "fastcgi" || framework == "fcgi") {
224ce89b 600 framework = "fastcgi";
7c673cae
FG
601 std::string uri_prefix;
602 config->get_val("prefix", "", &uri_prefix);
603 RGWProcessEnv fcgi_pe = { store, &rest, olog, 0, uri_prefix, auth_registry };
604
605 fe = new RGWFCGXFrontend(fcgi_pe, config);
606 }
607#endif /* WITH_RADOSGW_FCGI_FRONTEND */
608
224ce89b
WB
609 service_map_meta["frontend_type#" + stringify(fe_count)] = framework;
610 service_map_meta["frontend_config#" + stringify(fe_count)] = config->get_config();
611
7c673cae
FG
612 if (fe == NULL) {
613 dout(0) << "WARNING: skipping unknown framework: " << framework << dendl;
614 continue;
615 }
616
617 dout(0) << "starting handler: " << fiter->first << dendl;
618 int r = fe->init();
619 if (r < 0) {
620 derr << "ERROR: failed initializing frontend" << dendl;
621 return -r;
622 }
623 r = fe->run();
624 if (r < 0) {
625 derr << "ERROR: failed run" << dendl;
626 return -r;
627 }
628
629 fes.push_back(fe);
630 }
631
9f95a23c 632 r = store->getRados()->register_to_service_map("rgw", service_map_meta);
224ce89b
WB
633 if (r < 0) {
634 derr << "ERROR: failed to register to service map: " << cpp_strerror(-r) << dendl;
635
636 /* ignore error */
637 }
638
639
7c673cae 640 // add a watcher to respond to realm configuration changes
b3b6e05e 641 RGWPeriodPusher pusher(&dp, store, null_yield);
9f95a23c 642 RGWFrontendPauser pauser(fes, implicit_tenant_context, &pusher);
f6b5b4d7
TL
643 auto reloader = std::make_unique<RGWRealmReloader>(store,
644 service_map_meta, &pauser);
7c673cae 645
b3b6e05e 646 RGWRealmWatcher realm_watcher(&dp, g_ceph_context, store->svc()->zone->get_realm());
f6b5b4d7 647 realm_watcher.add_watcher(RGWRealmNotify::Reload, *reloader);
7c673cae
FG
648 realm_watcher.add_watcher(RGWRealmNotify::ZonesNeedPeriod, pusher);
649
650#if defined(HAVE_SYS_PRCTL_H)
651 if (prctl(PR_SET_DUMPABLE, 1) == -1) {
652 cerr << "warning: unable to set dumpable flag: " << cpp_strerror(errno) << std::endl;
653 }
654#endif
655
656 wait_shutdown();
657
658 derr << "shutting down" << dendl;
659
f6b5b4d7
TL
660 reloader.reset(); // stop the realm reloader
661
7c673cae
FG
662 for (list<RGWFrontend *>::iterator liter = fes.begin(); liter != fes.end();
663 ++liter) {
664 RGWFrontend *fe = *liter;
665 fe->stop();
666 }
667
668 for (list<RGWFrontend *>::iterator liter = fes.begin(); liter != fes.end();
669 ++liter) {
670 RGWFrontend *fe = *liter;
671 fe->join();
672 delete fe;
673 }
674
675 for (list<RGWFrontendConfig *>::iterator liter = configs.begin();
676 liter != configs.end(); ++liter) {
677 RGWFrontendConfig *fec = *liter;
678 delete fec;
679 }
680
b32b8144 681 unregister_async_signal_handler(SIGHUP, sighup_handler);
7c673cae
FG
682 unregister_async_signal_handler(SIGTERM, handle_sigterm);
683 unregister_async_signal_handler(SIGINT, handle_sigterm);
684 unregister_async_signal_handler(SIGUSR1, handle_sigterm);
685 shutdown_async_signal_handler();
686
687 rgw_log_usage_finalize();
7c673cae
FG
688 delete olog;
689
690 RGWStoreManager::close_storage(store);
11fdf7f2 691 rgw::auth::s3::LDAPEngine::shutdown();
7c673cae
FG
692 rgw_tools_cleanup();
693 rgw_shutdown_resolver();
11fdf7f2 694 rgw_http_client_cleanup();
f67539c2 695 rgw_kmip_client_cleanup();
94b18763 696 rgw::curl::cleanup_curl();
9f95a23c 697 g_conf().remove_observer(&implicit_tenant_context);
eafe8130
TL
698#ifdef WITH_RADOSGW_AMQP_ENDPOINT
699 rgw::amqp::shutdown();
700#endif
9f95a23c
TL
701#ifdef WITH_RADOSGW_KAFKA_ENDPOINT
702 rgw::kafka::shutdown();
703#endif
7c673cae
FG
704
705 rgw_perf_stop(g_ceph_context);
706
707 dout(1) << "final shutdown" << dendl;
708
709 signal_fd_finalize();
710
711 return 0;
712}
9f95a23c
TL
713
714extern "C" {
715
716int radosgw_main(int argc, const char** argv)
717{
718 return radosgw_Main(argc, argv);
719}
720
721} /* extern "C" */
722