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