From: Yehuda Sadeh Date: Fri, 19 Feb 2016 01:14:07 +0000 (-0800) Subject: Merge remote-tracking branch 'origin/master' into wip-rgw-new-multisite X-Git-Tag: v10.1.0~354^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=4d494d5b05a1dc6b41b858eeb293394592abf60c;p=ceph.git Merge remote-tracking branch 'origin/master' into wip-rgw-new-multisite Signed-off-by: Yehuda Sadeh Conflicts: src/CMakeLists.txt src/rgw/Makefile.am src/rgw/rgw_admin.cc src/rgw/rgw_common.h src/rgw/rgw_main.cc src/rgw/rgw_op.cc src/rgw/rgw_rados.h src/rgw/rgw_rest_s3.cc src/test/Makefile-client.am --- 4d494d5b05a1dc6b41b858eeb293394592abf60c diff --cc src/CMakeLists.txt index f30d949fa62,4850e8c945b..d6bb021be27 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@@ -1136,81 -1137,70 +1138,86 @@@ if(${WITH_RADOSGW} rgw/rgw_acl.cc rgw/rgw_acl_s3.cc rgw/rgw_acl_swift.cc - rgw/rgw_client_io.cc - rgw/rgw_fcgi.cc - rgw/rgw_xml.cc - rgw/rgw_usage.cc - rgw/rgw_json_enc.cc - rgw/rgw_user.cc - rgw/rgw_bucket.cc - rgw/rgw_tools.cc - rgw/rgw_rados.cc - rgw/rgw_http_client.cc - rgw/rgw_rest_client.cc - rgw/rgw_rest_conn.cc - rgw/rgw_op.cc + rgw/rgw_auth_s3.cc rgw/rgw_basic_types.cc - rgw/rgw_common.cc + rgw/rgw_bucket.cc rgw/rgw_cache.cc + rgw/rgw_client_io.cc + rgw/rgw_common.cc + rgw/rgw_cors.cc + rgw/rgw_cors_s3.cc + rgw/rgw_dencoder.cc + rgw/rgw_env.cc + rgw/rgw_fcgi.cc rgw/rgw_formats.cc + rgw/rgw_frontend.cc + rgw/rgw_gc.cc + rgw/rgw_http_client.cc + rgw/rgw_json_enc.cc + rgw/rgw_keystone.cc + rgw/rgw_loadgen.cc rgw/rgw_log.cc + rgw/rgw_metadata.cc rgw/rgw_multi.cc - rgw/rgw_policy_s3.cc - rgw/rgw_gc.cc rgw/rgw_multi_del.cc - rgw/rgw_env.cc - rgw/rgw_cors.cc - rgw/rgw_cors_s3.cc - rgw/rgw_auth_s3.cc - rgw/rgw_metadata.cc - rgw/rgw_replica_log.cc - rgw/rgw_keystone.cc - rgw/rgw_quota.cc + rgw/rgw_sync.cc + rgw/rgw_data_sync.cc - rgw/rgw_dencoder.cc + rgw/rgw_period_history.cc + rgw/rgw_period_puller.cc + rgw/rgw_period_pusher.cc + rgw/rgw_realm_reloader.cc + rgw/rgw_realm_watcher.cc + rgw/rgw_coroutine.cc + rgw/rgw_cr_rados.cc rgw/rgw_object_expirer_core.cc + rgw/rgw_op.cc + rgw/rgw_os_lib.cc + rgw/rgw_policy_s3.cc + rgw/rgw_process.cc + rgw/rgw_quota.cc + rgw/rgw_rados.cc + rgw/rgw_replica_log.cc + rgw/rgw_request.cc + rgw/rgw_resolve.cc + rgw/rgw_rest_bucket.cc + rgw/rgw_rest.cc + rgw/rgw_rest_client.cc + rgw/rgw_rest_config.cc + rgw/rgw_rest_conn.cc + rgw/rgw_rest_log.cc + rgw/rgw_rest_metadata.cc + rgw/rgw_rest_opstate.cc ++ rgw/rgw_rest_realm.cc + rgw/rgw_rest_replica_log.cc + rgw/rgw_rest_s3.cc + rgw/rgw_rest_swift.cc + rgw/rgw_rest_usage.cc + rgw/rgw_rest_user.cc + rgw/rgw_swift_auth.cc + rgw/rgw_swift.cc + rgw/rgw_tools.cc + rgw/rgw_usage.cc + rgw/rgw_user.cc rgw/rgw_website.cc - rgw/rgw_xml_enc.cc) + rgw/rgw_xml.cc + rgw/rgw_xml_enc.cc + ) add_library(rgw_a STATIC ${rgw_a_srcs}) + target_include_directories(rgw_a PUBLIC "${CMAKE_SOURCE_DIR}/src/civetweb/include") + target_link_libraries(rgw_a librados cls_rgw_client cls_refcount_client + cls_log_client cls_statelog_client cls_timeindex_client cls_version_client + cls_replica_log_client cls_user_client curl global expat) - include_directories("${CMAKE_SOURCE_DIR}/src/civetweb/include") + if(HAVE_BOOST_ASIO_COROUTINE) + target_compile_definitions(rgw_a PUBLIC "HAVE_BOOST_ASIO_COROUTINE") + endif() set(radosgw_srcs - rgw/rgw_resolve.cc - rgw/rgw_rest.cc - rgw/rgw_rest_swift.cc - rgw/rgw_rest_s3.cc - rgw/rgw_rest_usage.cc - rgw/rgw_rest_user.cc - rgw/rgw_rest_bucket.cc - rgw/rgw_rest_metadata.cc - rgw/rgw_replica_log.cc - rgw/rgw_rest_log.cc - rgw/rgw_rest_opstate.cc - rgw/rgw_rest_replica_log.cc - rgw/rgw_rest_config.cc - rgw/rgw_rest_realm.cc - rgw/rgw_http_client.cc - rgw/rgw_swift.cc - rgw/rgw_swift_auth.cc - rgw/rgw_loadgen.cc + rgw/rgw_fcgi_process.cc + rgw/rgw_loadgen_process.cc rgw/rgw_civetweb.cc + rgw/rgw_civetweb_frontend.cc rgw/rgw_civetweb_log.cc civetweb/src/civetweb.c rgw/rgw_main.cc) diff --cc src/common/config_opts.h index a36bcc003c8,65774387ab9..160ed36cb01 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@@ -1201,19 -1202,25 +1202,33 @@@ OPTION(rgw_thread_pool_size, OPT_INT, 1 OPTION(rgw_num_control_oids, OPT_INT, 8) OPTION(rgw_num_rados_handles, OPT_U32, 1) + /* The following are tunables for caches of RGW NFS (and other file + * client) objects. + * + * The file handle cache is a partitioned hash table + * (fhcache_partitions), each with a closed hash part and backing + * b-tree mapping. The number of partions is expected to be a small + * prime, the cache size something larger but less than 5K, the total + * size of the cache is n_part * cache_size. + */ + OPTION(rgw_nfs_lru_lanes, OPT_INT, 5) + OPTION(rgw_nfs_lru_lane_hiwat, OPT_INT, 911) + OPTION(rgw_nfs_fhcache_partitions, OPT_INT, 3) + OPTION(rgw_nfs_fhcache_size, OPT_INT, 2017) /* 3*2017=6051 */ + OPTION(rgw_zone, OPT_STR, "") // zone name OPTION(rgw_zone_root_pool, OPT_STR, ".rgw.root") // pool where zone specific info is stored +OPTION(rgw_default_zone_info_oid, OPT_STR, "default.zone") // oid where default zone info is stored OPTION(rgw_region, OPT_STR, "") // region name -OPTION(rgw_region_root_pool, OPT_STR, ".rgw.root") // pool where all region info is stored OPTION(rgw_default_region_info_oid, OPT_STR, "default.region") // oid where default region info is stored +OPTION(rgw_zonegroup, OPT_STR, "") // zone group name +OPTION(rgw_zonegroup_root_pool, OPT_STR, ".rgw.root") // pool where all zone group info is stored +OPTION(rgw_default_zonegroup_info_oid, OPT_STR, "default.zonegroup") // oid where default zone group info is stored +OPTION(rgw_realm, OPT_STR, "") // realm name +OPTION(rgw_realm_root_pool, OPT_STR, ".rgw.root") // pool where all realm info is stored +OPTION(rgw_default_realm_info_oid, OPT_STR, "default.realm") // oid where default realm info is stored +OPTION(rgw_period_root_pool, OPT_STR, ".rgw.root") // pool where all period info is stored +OPTION(rgw_period_latest_epoch_info_oid, OPT_STR, ".latest_epoch") // oid where current period info is stored OPTION(rgw_log_nonexistent_bucket, OPT_BOOL, false) OPTION(rgw_log_object_name, OPT_STR, "%Y-%m-%d-%H-%i-%n") // man date to see codes (a subset are supported) OPTION(rgw_log_object_name_utc, OPT_BOOL, false) diff --cc src/rgw/Makefile.am index 808a31773b6,775ee986c3d..cb301df911d --- a/src/rgw/Makefile.am +++ b/src/rgw/Makefile.am @@@ -25,52 -16,64 +24,75 @@@ librgw_la_SOURCES = rgw/rgw_acl.cc \ rgw/rgw_acl_s3.cc \ rgw/rgw_acl_swift.cc \ - rgw/rgw_client_io.cc \ - rgw/rgw_auth_s3.cc \ + rgw/rgw_coroutine.cc \ + rgw/rgw_cr_rados.cc \ - rgw/rgw_fcgi.cc \ - rgw/rgw_xml.cc \ - rgw/rgw_usage.cc \ - rgw/rgw_json_enc.cc \ - rgw/rgw_xml_enc.cc \ - rgw/rgw_user.cc \ - rgw/rgw_bucket.cc\ + rgw/rgw_tools.cc \ - rgw/rgw_rados.cc \ - rgw/rgw_http_client.cc \ - rgw/rgw_rest_client.cc \ - rgw/rgw_rest_conn.cc \ - rgw/rgw_op.cc \ rgw/rgw_basic_types.cc \ - rgw/rgw_common.cc \ + rgw/rgw_bucket.cc \ rgw/rgw_cache.cc \ + rgw/rgw_client_io.cc \ + rgw/rgw_common.cc \ + rgw/rgw_cors.cc \ + rgw/rgw_cors_s3.cc \ + rgw/rgw_dencoder.cc \ + rgw/rgw_env.cc \ + rgw/rgw_fcgi.cc \ rgw/rgw_formats.cc \ + rgw/rgw_frontend.cc \ + rgw/rgw_gc.cc \ + rgw/rgw_http_client.cc \ + rgw/rgw_json_enc.cc \ + rgw/rgw_keystone.cc \ + rgw/rgw_loadgen.cc \ rgw/rgw_log.cc \ + rgw/rgw_metadata.cc \ rgw/rgw_multi.cc \ - rgw/rgw_policy_s3.cc \ - rgw/rgw_gc.cc \ rgw/rgw_multi_del.cc \ - rgw/rgw_env.cc \ - rgw/rgw_cors.cc \ - rgw/rgw_cors_s3.cc \ + rgw/rgw_auth_s3.cc \ - rgw/rgw_metadata.cc \ - rgw/rgw_replica_log.cc \ - rgw/rgw_keystone.cc \ - rgw/rgw_quota.cc \ - rgw/rgw_dencoder.cc \ + rgw/rgw_period_history.cc \ + rgw/rgw_period_puller.cc \ + rgw/rgw_period_pusher.cc \ + rgw/rgw_realm_reloader.cc \ + rgw/rgw_realm_watcher.cc \ - rgw/rgw_object_expirer_core.cc \ - rgw/rgw_website.cc \ + rgw/rgw_sync.cc \ - rgw/rgw_data_sync.cc ++ rgw/rgw_data_sync.cc \ + rgw/rgw_object_expirer_core.cc \ + rgw/rgw_op.cc \ + rgw/rgw_os_lib.cc \ + rgw/rgw_policy_s3.cc \ + rgw/rgw_process.cc \ + rgw/rgw_quota.cc \ + rgw/rgw_rados.cc \ + rgw/rgw_replica_log.cc \ + rgw/rgw_request.cc \ + rgw/rgw_resolve.cc \ + rgw/rgw_rest_bucket.cc \ + rgw/rgw_rest.cc \ + rgw/rgw_rest_client.cc \ + rgw/rgw_rest_config.cc \ + rgw/rgw_rest_conn.cc \ + rgw/rgw_rest_log.cc \ + rgw/rgw_rest_metadata.cc \ + rgw/rgw_rest_opstate.cc \ ++ rgw/rgw_rest_realm.cc \ + rgw/rgw_rest_replica_log.cc \ + rgw/rgw_rest_s3.cc \ + rgw/rgw_rest_swift.cc \ + rgw/rgw_rest_usage.cc \ + rgw/rgw_rest_user.cc \ + rgw/rgw_swift_auth.cc \ + rgw/rgw_swift.cc \ - rgw/rgw_tools.cc \ + rgw/rgw_usage.cc \ + rgw/rgw_user.cc \ + rgw/rgw_file.cc \ + rgw/librgw.cc \ + rgw/rgw_xml.cc \ + rgw/rgw_xml_enc.cc \ + rgw/rgw_website.cc - librgw_la_CXXFLAGS = -Woverloaded-virtual ${AM_CXXFLAGS} - noinst_LTLIBRARIES += librgw.la + librgw_la_CXXFLAGS = -Woverloaded-virtual -fPIC -I$(srcdir)/xxHash \ + ${AM_CXXFLAGS} ++# noinst_LTLIBRARIES += librgw.la LIBRGW_DEPS += \ $(LIBRADOS) \ diff --cc src/rgw/librgw.cc index f9b39aeba59,7deaecc0611..ada07af3653 --- a/src/rgw/librgw.cc +++ b/src/rgw/librgw.cc @@@ -27,106 -54,539 +54,540 @@@ #define dout_subsys ceph_subsys_rgw - int librgw_create(librgw_t *rgw, const char * const id) - { - CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT); - if (id) { - iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id); - } - CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0, - "rgw_data"); - cct->_conf->set_val("log_to_stderr", "false"); // quiet by default - cct->_conf->set_val("err_to_stderr", "true"); // quiet by default - cct->_conf->parse_env(); // environment variables override - cct->_conf->apply_changes(NULL); - - common_init_finish(cct); - *rgw = cct; - return 0; - } + bool global_stop = false; - int librgw_acl_bin2xml(librgw_t rgw, const char *bin, int bin_len, char **xml) - { - try { - // convert to bufferlist - bufferlist bl; - bl.append(bin, bin_len); - - // convert to RGWAccessControlPolicy - RGWAccessControlPolicy_S3 acl((CephContext *)rgw); - bufferlist::iterator bli(bl.begin()); - acl.decode(bli); - - // convert to XML stringstream - stringstream ss; - acl.to_xml(ss); - - // convert to XML C string - *xml = strdup(ss.str().c_str()); - if (!*xml) - return -ENOBUFS; - return 0; - } - catch (const std::exception &e) { - lderr(rgw) << "librgw_acl_bin2xml: caught exception " << e.what() << dendl; - return -2000; + namespace rgw { + + using std::string; + + static std::mutex librgw_mtx; + + RGWLib rgwlib; + + class C_InitTimeout : public Context { + public: + C_InitTimeout() {} + void finish(int r) { + derr << "Initialization timeout, failed to initialize" << dendl; + exit(1); + } + }; + + void RGWLibProcess::checkpoint() + { + m_tp.drain(&req_wq); } - catch (...) { - lderr(rgw) << "librgw_acl_bin2xml: caught unknown exception " << dendl; - return -2000; + + void RGWLibProcess::run() + { + while (! shutdown) { + lsubdout(cct, rgw, 5) << "RGWLibProcess GC" << dendl; + unique_lock uniq(mtx); + restart: + int cur_gen = gen; + for (auto iter = mounted_fs.begin(); iter != mounted_fs.end(); + ++iter) { + RGWLibFS* fs = iter->first->ref(); + uniq.unlock(); + fs->gc(); + fs->rele(); + uniq.lock(); + if (cur_gen != gen) + goto restart; /* invalidated */ + } + uniq.unlock(); + std::this_thread::sleep_for(std::chrono::seconds(120)); + } } - } - void librgw_free_xml(librgw_t rgw, char *xml) - { - free(xml); - } + void RGWLibProcess::handle_request(RGWRequest* r) + { + /* + * invariant: valid requests are derived from RGWLibRequst + */ + RGWLibRequest* req = static_cast(r); - int librgw_acl_xml2bin(librgw_t rgw, const char *xml, char **bin, int *bin_len) - { - char *bin_ = NULL; - try { - RGWACLXMLParser_S3 parser((CephContext *)rgw); - if (!parser.init()) { - return -1000; + // XXX move RGWLibIO and timing setup into process_request + + #if 0 /* XXX */ + utime_t tm = ceph_clock_now(NULL); + #endif + + RGWLibIO io_ctx; + + int ret = process_request(req, &io_ctx); + if (ret < 0) { + /* we don't really care about return code */ + dout(20) << "process_request() returned " << ret << dendl; + + } + delete req; + } /* handle_request */ + + int RGWLibProcess::process_request(RGWLibRequest* req) + { + // XXX move RGWLibIO and timing setup into process_request + + #if 0 /* XXX */ + utime_t tm = ceph_clock_now(NULL); + #endif + + RGWLibIO io_ctx; + + int ret = process_request(req, &io_ctx); + if (ret < 0) { + /* we don't really care about return code */ + dout(20) << "process_request() returned " << ret << dendl; } - if (!parser.parse(xml, strlen(xml), true)) { + return ret; + } /* process_request */ + + static inline void abort_req(struct req_state *s, RGWOp *op, int err_no) + { + if (!s) + return; + + /* XXX the dump_errno and dump_bucket_from_state behaviors in + * the abort_early (rgw_rest.cc) might be valuable, but aren't + * safe to call presently as they return HTTP data */ + + perfcounter->inc(l_rgw_failed_req); + } /* abort_req */ + + int RGWLibProcess::process_request(RGWLibRequest* req, RGWLibIO* io) + { + int ret = 0; + bool should_log = true; // XXX + + dout(1) << "====== " << __func__ + << " starting new request req=" << hex << req << dec + << " ======" << dendl; + + /* + * invariant: valid requests are derived from RGWOp--well-formed + * requests should have assigned RGWRequest::op in their descendant + * constructor--if not, the compiler can find it, at the cost of + * a runtime check + */ + RGWOp *op = (req->op) ? req->op : dynamic_cast(req); + if (! op) { + dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl; return -EINVAL; } - RGWAccessControlPolicy_S3 *policy = - (RGWAccessControlPolicy_S3 *)parser.find_first("AccessControlPolicy"); - if (!policy) { - return -1001; + + io->init(req->cct); + + perfcounter->inc(l_rgw_req); + + RGWEnv& rgw_env = io->get_env(); + + /* XXX + * until major refactoring of req_state and req_info, we need + * to build their RGWEnv boilerplate from the RGWLibRequest, + * pre-staging any strings (HTTP_HOST) that provoke a crash when + * not found + */ + + /* XXX for now, use ""; could be a legit hostname, or, in future, + * perhaps a tenant (Yehuda) */ + rgw_env.set("HTTP_HOST", ""); + + /* XXX and -then- bloat up req_state with string copies from it */ + struct req_state rstate(req->cct, &rgw_env, req->get_user()); + struct req_state *s = &rstate; + + // XXX fix this + s->cio = io; + + RGWObjectCtx rados_ctx(store, s); // XXX holds std::map + + /* XXX and -then- stash req_state pointers everywhere they are needed */ + ret = req->init(rgw_env, &rados_ctx, io, s); + if (ret < 0) { + dout(10) << "failed to initialize request" << dendl; + abort_req(s, op, ret); + goto done; + } + + /* req is-a RGWOp, currently initialized separately */ + ret = req->op_init(); + if (ret < 0) { + dout(10) << "failed to initialize RGWOp" << dendl; + abort_req(s, op, ret); + goto done; + } + + /* XXX authorize does less here then in the REST path, e.g., + * the user's info is cached, but still incomplete */ + req->log(s, "authorizing"); + ret = req->authorize(); + if (ret < 0) { + dout(10) << "failed to authorize request" << dendl; + abort_req(s, op, ret); + goto done; + } + + req->log(s, "reading op permissions"); + ret = req->read_permissions(op); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "init op"); + ret = op->init_processing(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "verifying op mask"); + ret = op->verify_op_mask(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "verifying op permissions"); + ret = op->verify_permission(); + if (ret < 0) { + if (s->system_request) { + dout(2) << "overriding permissions due to system operation" << dendl; + } else { + abort_req(s, op, ret); + goto done; + } + } + + req->log(s, "verifying op params"); + ret = op->verify_params(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "executing"); + op->pre_exec(); + op->execute(); + op->complete(); + + done: + int r = io->complete_request(); + if (r < 0) { + dout(0) << "ERROR: io->complete_request() returned " << r << dendl; + } + if (should_log) { + rgw_log_op(store, s, (op ? op->name() : "unknown"), olog); + } + + int http_ret = s->err.http_ret; + + req->log_format(s, "http status=%d", http_ret); + + dout(1) << "====== " << __func__ + << " req done req=" << hex << req << dec << " http_status=" + << http_ret + << " ======" << dendl; + + return (ret < 0 ? ret : s->err.ret); + } /* process_request */ + + int RGWLibProcess::start_request(RGWLibContinuedReq* req) + { + + dout(1) << "====== " << __func__ + << " starting new continued request req=" << hex << req << dec + << " ======" << dendl; + + /* + * invariant: valid requests are derived from RGWOp--well-formed + * requests should have assigned RGWRequest::op in their descendant + * constructor--if not, the compiler can find it, at the cost of + * a runtime check + */ + RGWOp *op = (req->op) ? req->op : dynamic_cast(req); + if (! op) { + dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl; + return -EINVAL; + } + + struct req_state* s = req->get_state(); + + /* req is-a RGWOp, currently initialized separately */ + int ret = req->op_init(); + if (ret < 0) { + dout(10) << "failed to initialize RGWOp" << dendl; + abort_req(s, op, ret); + goto done; + } + + /* XXX authorize does less here then in the REST path, e.g., + * the user's info is cached, but still incomplete */ + req->log(s, "authorizing"); + ret = req->authorize(); + if (ret < 0) { + dout(10) << "failed to authorize request" << dendl; + abort_req(s, op, ret); + goto done; + } + + req->log(s, "reading op permissions"); + ret = req->read_permissions(op); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "init op"); + ret = op->init_processing(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "verifying op mask"); + ret = op->verify_op_mask(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; + } + + req->log(s, "verifying op permissions"); + ret = op->verify_permission(); + if (ret < 0) { + if (s->system_request) { + dout(2) << "overriding permissions due to system operation" << dendl; + } else { + abort_req(s, op, ret); + goto done; + } + } + + req->log(s, "verifying op params"); + ret = op->verify_params(); + if (ret < 0) { + abort_req(s, op, ret); + goto done; } - bufferlist bl; - policy->encode(bl); - bin_ = (char*)malloc(bl.length()); - if (!bin_) { - return -ENOBUFS; + op->pre_exec(); + req->exec_start(); + + done: + return (ret < 0 ? ret : s->err.ret); + } + + int RGWLibProcess::finish_request(RGWLibContinuedReq* req) + { + RGWOp *op = (req->op) ? req->op : dynamic_cast(req); + if (! op) { + dout(1) << "failed to derive cognate RGWOp (invalid op?)" << dendl; + return -EINVAL; } - int bin_len_ = bl.length(); - bl.copy(0, bin_len_, bin_); - *bin = bin_; - *bin_len = bin_len_; + int ret = req->exec_finish(); + int op_ret = op->get_ret(); + + dout(1) << "====== " << __func__ + << " finishing continued request req=" << hex << req << dec + << " op status=" << op_ret + << " ======" << dendl; + + return ret; + } + + int RGWLibFrontend::init() + { + pprocess = new RGWLibProcess(g_ceph_context, &env, + g_conf->rgw_thread_pool_size, conf); return 0; } - catch (const std::exception &e) { - lderr(rgw) << "librgw_acl_bin2xml: caught exception " << e.what() << dendl; + + int RGWLib::init() + { + vector args; + return init(args); } - catch (...) { - lderr(rgw) << "librgw_acl_bin2xml: caught unknown exception " << dendl; + + int RGWLib::init(vector& args) + { + int r = 0; + + /* alternative default for module */ + vector def_args; + def_args.push_back("--debug-rgw=1/5"); + def_args.push_back("--keyring=$rgw_data/keyring"); + def_args.push_back("--log-file=/var/log/radosgw/$cluster-$name.log"); + + global_init(&def_args, args, + CEPH_ENTITY_TYPE_CLIENT, + CODE_ENVIRONMENT_DAEMON, + CINIT_FLAG_UNPRIVILEGED_DAEMON_DEFAULTS); + + Mutex mutex("main"); + SafeTimer init_timer(g_ceph_context, mutex); + init_timer.init(); + mutex.Lock(); + init_timer.add_event_after(g_conf->rgw_init_timeout, new C_InitTimeout); + mutex.Unlock(); + + common_init_finish(g_ceph_context); + + rgw_tools_init(g_ceph_context); + + rgw_init_resolver(); + + store = RGWStoreManager::get_storage(g_ceph_context, + g_conf->rgw_enable_gc_threads, - g_conf->rgw_enable_quota_threads); ++ g_conf->rgw_enable_quota_threads, ++ g_conf->rgw_run_sync_thread); + + if (!store) { + mutex.Lock(); + init_timer.cancel_all_events(); + init_timer.shutdown(); + mutex.Unlock(); + + derr << "Couldn't init storage provider (RADOS)" << dendl; + return -EIO; + } + + r = rgw_perf_start(g_ceph_context); + - rgw_rest_init(g_ceph_context, store->region); ++ rgw_rest_init(g_ceph_context, store, store->get_zonegroup()); + + mutex.Lock(); + init_timer.cancel_all_events(); + init_timer.shutdown(); + mutex.Unlock(); + + if (r) + return -EIO; + + rgw_user_init(store); + rgw_bucket_init(store->meta_mgr); + rgw_log_usage_init(g_ceph_context, store); + + // XXX ex-RGWRESTMgr_lib, mgr->set_logging(true) + + if (!g_conf->rgw_ops_log_socket_path.empty()) { + olog = new OpsLogSocket(g_ceph_context, g_conf->rgw_ops_log_data_backlog); + olog->init(g_conf->rgw_ops_log_socket_path); + } + + int port = 80; + RGWProcessEnv env = { store, &rest, olog, port }; + + fec = new RGWFrontendConfig("rgwlib"); + fe = new RGWLibFrontend(env, fec); + + fe->init(); + if (r < 0) { + derr << "ERROR: failed initializing frontend" << dendl; + return r; + } + + fe->run(); + + return 0; + } /* RGWLib::init() */ + + int RGWLib::stop() + { + derr << "shutting down" << dendl; + + fe->stop(); + + fe->join(); + + delete fe; + + rgw_log_usage_finalize(); + + delete olog; + + RGWStoreManager::close_storage(store); + + rgw_tools_cleanup(); + rgw_shutdown_resolver(); + + rgw_perf_stop(g_ceph_context); + + dout(1) << "final shutdown" << dendl; + g_ceph_context->put(); + + ceph::crypto::shutdown(); + + return 0; + } /* RGWLib::stop() */ + + int RGWLibIO::set_uid(RGWRados *store, const rgw_user& uid) + { + int ret = rgw_get_user_info_by_uid(store, uid, user_info, NULL); + if (ret < 0) { + derr << "ERROR: failed reading user info: uid=" << uid << " ret=" + << ret << dendl; + } + return ret; } - if (!bin_) - free(bin_); - bin_ = NULL; - return -2000; - } - void librgw_free_bin(librgw_t rgw, char *bin) + int RGWLibRequest::read_permissions(RGWOp* op) { + int ret = + rgw_build_bucket_policies(rgwlib.get_store(), get_state()); + if (ret < 0) { + ldout(get_state()->cct, 10) << "read_permissions on " + << get_state()->bucket << ":" + << get_state()->object + << " only_bucket=" << only_bucket() + << " ret=" << ret << dendl; + if (ret == -ENODATA) + ret = -EACCES; + } + return ret; + } /* RGWLibRequest::read_permissions */ + + int RGWHandler_Lib::authorize() + { + /* TODO: handle + * 1. subusers + * 2. anonymous access + * 3. system access + * 4. ? + * + * Much or all of this depends on handling the cached authorization + * correctly (e.g., dealing with keystone) at mount time. + */ + s->perm_mask = RGW_PERM_FULL_CONTROL; + + // populate the owner info + s->owner.set_id(s->user->user_id); + s->owner.set_name(s->user->display_name); + + return 0; + } /* RGWHandler_Lib::authorize */ + + } /* namespace rgw */ + + extern "C" { + + int librgw_create(librgw_t* rgw, int argc, char **argv) { - free(bin); + using namespace rgw; + + int rc = -EINVAL; + + if (! g_ceph_context) { + std::lock_guard lg(librgw_mtx); + if (! g_ceph_context) { + vector args; + argv_to_vec(argc, const_cast(argv), args); + rc = rgwlib.init(args); + } + } + + *rgw = g_ceph_context->get(); + + return rc; } void librgw_shutdown(librgw_t rgw) diff --cc src/rgw/rgw_admin.cc index fb4c2a927b9,885aca66305..3d94720aedb --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@@ -47,193 -43,150 +47,194 @@@ static RGWRados *store = NULL void _usage() { - cerr << "usage: radosgw-admin [options...]" << std::endl; - cerr << "commands:\n"; - cerr << " user create create a new user\n" ; - cerr << " user modify modify user\n"; - cerr << " user info get user info\n"; - cerr << " user rm remove user\n"; - cerr << " user suspend suspend a user\n"; - cerr << " user enable re-enable user after suspension\n"; - cerr << " user check check user info\n"; - cerr << " user stats show user stats as accounted by quota subsystem\n"; - cerr << " caps add add user capabilities\n"; - cerr << " caps rm remove user capabilities\n"; - cerr << " subuser create create a new subuser\n" ; - cerr << " subuser modify modify subuser\n"; - cerr << " subuser rm remove subuser\n"; - cerr << " key create create access key\n"; - cerr << " key rm remove access key\n"; - cerr << " bucket list list buckets\n"; - cerr << " bucket link link bucket to specified user\n"; - cerr << " bucket unlink unlink bucket from specified user\n"; - cerr << " bucket stats returns bucket statistics\n"; - cerr << " bucket rm remove bucket\n"; - cerr << " bucket check check bucket index\n"; - cerr << " object rm remove object\n"; - cerr << " object unlink unlink object from bucket index\n"; - cerr << " objects expire run expired objects cleanup\n"; - cerr << " period prepare prepare a new period\n"; - cerr << " period delete delete a period\n"; - cerr << " period get get period info\n"; - cerr << " period get-current get current period info\n"; - cerr << " period pull pull a period\n"; - cerr << " period push push a period\n"; - cerr << " period list list all periods\n"; - cerr << " period update update the staging period\n"; - cerr << " period commit commit the staging period\n"; - cerr << " quota set set quota params\n"; - cerr << " quota enable enable quota\n"; - cerr << " quota disable disable quota\n"; - cerr << " realm create create a new realm\n"; - cerr << " realm delete delete a realm\n"; - cerr << " realm get show realm info\n"; - cerr << " realm get-default get default realm name\n"; - cerr << " realm list list realms\n"; - cerr << " realm list-periods list all realm periods\n"; - cerr << " realm remove remove a zonegroup from the realm\n"; - cerr << " realm rename rename a realm\n"; - cerr << " realm set set realm info (requires infile)\n"; - cerr << " realm default set realm as default\n"; - cerr << " realm pull pull a realm and its current period\n"; - cerr << " zonegroup add add a zone to a zonegroup\n"; - cerr << " zonegroup create create a new zone group info\n"; - cerr << " zonegroup default set default zone group\n"; - cerr << " zonegroup delete delete a zone group info\n"; - cerr << " zonegroup get show zone group info\n"; - cerr << " zonegroup modify set/clear zonegroup master status\n"; - cerr << " zonegroup set set zone group info (requires infile)\n"; - cerr << " zonegroup rename rename a zone group\n"; - cerr << " zonegroup list list all zone groups set on this cluster\n"; - cerr << " zonegroup-map get show zonegroup-map\n"; - cerr << " zonegroup-map set set zonegroup-map (requires infile)\n"; - cerr << " zone create create a new zone\n"; - cerr << " zone get show zone cluster params\n"; - cerr << " zone modify set/clear zone master status\n"; - cerr << " zone set set zone cluster params (requires infile)\n"; - cerr << " zone list list all zones set on this cluster\n"; - cerr << " pool add add an existing pool for data placement\n"; - cerr << " pool rm remove an existing pool from data placement set\n"; - cerr << " pools list list placement active set\n"; - cerr << " policy read bucket/object policy\n"; - cerr << " log list list log objects\n"; - cerr << " log show dump a log from specific object or (bucket + date\n"; - cerr << " + bucket-id)\n"; - cerr << " (NOTE: required to specify formatting of date\n"; - cerr << " to \"YYYY-MM-DD-hh\")\n"; - cerr << " log rm remove log object\n"; - cerr << " usage show show usage (by user, date range)\n"; - cerr << " usage trim trim usage (by user, date range)\n"; - cerr << " temp remove remove temporary objects that were created up to\n"; - cerr << " specified date (and optional time)\n"; - cerr << " gc list dump expired garbage collection objects (specify\n"; - cerr << " --include-all to list all entries, including unexpired)\n"; - cerr << " gc process manually process garbage\n"; - cerr << " metadata get get metadata info\n"; - cerr << " metadata put put metadata info\n"; - cerr << " metadata rm remove metadata info\n"; - cerr << " metadata list list metadata info\n"; - cerr << " mdlog list list metadata log\n"; - cerr << " mdlog trim trim metadata log (use start-date, end-date or\n"; - cerr << " start-marker, end-marker)\n"; - cerr << " mdlog status read metadata log status\n"; - cerr << " bilog list list bucket index log\n"; - cerr << " bilog trim trim bucket index log (use start-marker, end-marker)\n"; - cerr << " datalog list list data log\n"; - cerr << " datalog trim trim data log\n"; - cerr << " datalog status read data log status\n"; - cerr << " opstate list list stateful operations entries (use client_id,\n"; - cerr << " op_id, object)\n"; - cerr << " opstate set set state on an entry (use client_id, op_id, object, state)\n"; - cerr << " opstate renew renew state on an entry (use client_id, op_id, object)\n"; - cerr << " opstate rm remove entry (use client_id, op_id, object)\n"; - cerr << " replicalog get get replica metadata log entry\n"; - cerr << " replicalog update update replica metadata log entry\n"; - cerr << " replicalog delete delete replica metadata log entry\n"; - cerr << " orphans find init and run search for leaked rados objects\n"; - cerr << " orphans finish clean up search for leaked rados objects\n"; - cerr << "options:\n"; - cerr << " --uid= user id\n"; - cerr << " --subuser= subuser name\n"; - cerr << " --access-key= S3 access key\n"; - cerr << " --email=\n"; - cerr << " --secret/--secret-key=\n"; - cerr << " specify secret key\n"; - cerr << " --gen-access-key generate random access key (for S3)\n"; - cerr << " --gen-secret generate random secret key\n"; - cerr << " --key-type= key type, options are: swift, s3\n"; - cerr << " --temp-url-key[-2]= temp url key\n"; - cerr << " --access= Set access permissions for sub-user, should be one\n"; - cerr << " of read, write, readwrite, full\n"; - cerr << " --display-name=\n"; - cerr << " --max_buckets max number of buckets for a user\n"; - cerr << " --system set the system flag on the user\n"; - cerr << " --bucket=\n"; - cerr << " --pool=\n"; - cerr << " --object=\n"; - cerr << " --date=\n"; - cerr << " --start-date=\n"; - cerr << " --end-date=\n"; - cerr << " --bucket-id=\n"; - cerr << " --shard-id= optional for mdlog list\n"; - cerr << " required for: \n"; - cerr << " mdlog trim\n"; - cerr << " replica mdlog get/delete\n"; - cerr << " replica datalog get/delete\n"; - cerr << " --metadata-key= key to retrieve metadata from with metadata get\n"; - cerr << " --remote= remote to pull period\n"; - cerr << " --parent= parent period id\n"; - cerr << " --period= period id\n"; - cerr << " --epoch= period epoch\n"; - cerr << " --commit commit the period during 'period update'\n"; - cerr << " --master set as master\n"; - cerr << " --master-url master url\n"; - cerr << " --master-zonegroup= master zonegroup id\n"; - cerr << " --master-zone= master zone id\n"; - cerr << " --rgw-realm= realm name\n"; - cerr << " --realm-id= realm id\n"; - cerr << " --realm-new-name= realm new name\n"; - cerr << " --rgw-zonegroup= zonegroup name\n"; - cerr << " --rgw-zone= zone in which radosgw is running\n"; - cerr << " --zone-new-name= zone new name\n"; - cerr << " --default set entity (realm, zonegroup, zone) as default\n"; - cerr << " --endpoints= zone endpoints\n"; - cerr << " --fix besides checking bucket index, will also fix it\n"; - cerr << " --check-objects bucket check: rebuilds bucket index according to\n"; - cerr << " actual objects state\n"; - cerr << " --format= specify output format for certain operations: xml,\n"; - cerr << " json\n"; - cerr << " --purge-data when specified, user removal will also purge all the\n"; - cerr << " user data\n"; - cerr << " --purge-keys when specified, subuser removal will also purge all the\n"; - cerr << " subuser keys\n"; - cerr << " --purge-objects remove a bucket's objects before deleting it\n"; - cerr << " (NOTE: required to delete a non-empty bucket)\n"; - cerr << " --sync-stats option to 'user stats', update user stats with current\n"; - cerr << " stats reported by user's buckets indexes\n"; - cerr << " --show-log-entries= enable/disable dump of log entries on log show\n"; - cerr << " --show-log-sum= enable/disable dump of log summation on log show\n"; - cerr << " --skip-zero-entries log show only dumps entries that don't have zero value\n"; - cerr << " in one of the numeric field\n"; - cerr << " --infile specify a file to read in when setting data\n"; - cerr << " --state= specify a state for the opstate set command\n"; - cerr << " --replica-log-type replica log type (metadata, data, bucket), required for\n"; - cerr << " replica log operations\n"; - cerr << " --categories= comma separated list of categories, used in usage show\n"; - cerr << " --caps= list of caps (e.g., \"usage=read, write; user=read\"\n"; - cerr << " --yes-i-really-mean-it required for certain operations\n"; - cerr << " --reset-regions reset regionmap when regionmap update"; - cerr << "\n"; - cerr << " := \"YYYY-MM-DD[ hh:mm:ss]\"\n"; - cerr << "\nQuota options:\n"; - cerr << " --bucket specified bucket for quota command\n"; - cerr << " --max-objects specify max objects (negative value to disable)\n"; - cerr << " --max-size specify max size (in bytes, negative value to disable)\n"; - cerr << " --quota-scope scope of quota (bucket, user)\n"; - cerr << "\nOrphans search options:\n"; - cerr << " --pool data pool to scan for leaked rados objects in\n"; - cerr << " --num-shards num of shards to use for keeping the temporary scan info\n"; - cerr << "\n"; + cout << "usage: radosgw-admin [options...]" << std::endl; + cout << "commands:\n"; + cout << " user create create a new user\n" ; + cout << " user modify modify user\n"; + cout << " user info get user info\n"; + cout << " user rm remove user\n"; + cout << " user suspend suspend a user\n"; + cout << " user enable re-enable user after suspension\n"; + cout << " user check check user info\n"; + cout << " user stats show user stats as accounted by quota subsystem\n"; + cout << " caps add add user capabilities\n"; + cout << " caps rm remove user capabilities\n"; + cout << " subuser create create a new subuser\n" ; + cout << " subuser modify modify subuser\n"; + cout << " subuser rm remove subuser\n"; + cout << " key create create access key\n"; + cout << " key rm remove access key\n"; + cout << " bucket list list buckets\n"; + cout << " bucket link link bucket to specified user\n"; + cout << " bucket unlink unlink bucket from specified user\n"; + cout << " bucket stats returns bucket statistics\n"; + cout << " bucket rm remove bucket\n"; + cout << " bucket check check bucket index\n"; + cout << " object rm remove object\n"; + cout << " object unlink unlink object from bucket index\n"; + cout << " objects expire run expired objects cleanup\n"; ++ cout << " period prepare prepare a new period\n"; ++ cout << " period delete delete a period\n"; ++ cout << " period get get period info\n"; ++ cout << " period get-current get current period info\n"; ++ cout << " period pull pull a period\n"; ++ cout << " period push push a period\n"; ++ cout << " period list list all periods\n"; ++ cout << " period update update the staging period\n"; ++ cout << " period commit commit the staging period\n"; + cout << " quota set set quota params\n"; + cout << " quota enable enable quota\n"; + cout << " quota disable disable quota\n"; - cout << " region get show region info\n"; - cout << " regions list list all regions set on this cluster\n"; - cout << " region set set region info (requires infile)\n"; - cout << " region default set default region\n"; - cout << " region-map get show region-map\n"; - cout << " region-map set set region-map (requires infile)\n"; ++ cout << " realm create create a new realm\n"; ++ cout << " realm delete delete a realm\n"; ++ cout << " realm get show realm info\n"; ++ cout << " realm get-default get default realm name\n"; ++ cout << " realm list list realms\n"; ++ cout << " realm list-periods list all realm periods\n"; ++ cout << " realm remove remove a zonegroup from the realm\n"; ++ cout << " realm rename rename a realm\n"; ++ cout << " realm set set realm info (requires infile)\n"; ++ cout << " realm default set realm as default\n"; ++ cout << " realm pull pull a realm and its current period\n"; ++ cout << " zonegroup add add a zone to a zonegroup\n"; ++ cout << " zonegroup create create a new zone group info\n"; ++ cout << " zonegroup default set default zone group\n"; ++ cout << " zonegroup delete delete a zone group info\n"; ++ cout << " zonegroup get show zone group info\n"; ++ cout << " zonegroup modify set/clear zonegroup master status\n"; ++ cout << " zonegroup set set zone group info (requires infile)\n"; ++ cout << " zonegroup rename rename a zone group\n"; ++ cout << " zonegroup list list all zone groups set on this cluster\n"; ++ cout << " zonegroup-map get show zonegroup-map\n"; ++ cout << " zonegroup-map set set zonegroup-map (requires infile)\n"; ++ cout << " zone create create a new zone\n"; + cout << " zone get show zone cluster params\n"; ++ cout << " zone modify set/clear zone master status\n"; + cout << " zone set set zone cluster params (requires infile)\n"; + cout << " zone list list all zones set on this cluster\n"; + cout << " pool add add an existing pool for data placement\n"; + cout << " pool rm remove an existing pool from data placement set\n"; + cout << " pools list list placement active set\n"; + cout << " policy read bucket/object policy\n"; + cout << " log list list log objects\n"; + cout << " log show dump a log from specific object or (bucket + date\n"; + cout << " + bucket-id)\n"; + cout << " (NOTE: required to specify formatting of date\n"; + cout << " to \"YYYY-MM-DD-hh\")\n"; + cout << " log rm remove log object\n"; + cout << " usage show show usage (by user, date range)\n"; + cout << " usage trim trim usage (by user, date range)\n"; + cout << " temp remove remove temporary objects that were created up to\n"; + cout << " specified date (and optional time)\n"; + cout << " gc list dump expired garbage collection objects (specify\n"; + cout << " --include-all to list all entries, including unexpired)\n"; + cout << " gc process manually process garbage\n"; + cout << " metadata get get metadata info\n"; + cout << " metadata put put metadata info\n"; + cout << " metadata rm remove metadata info\n"; + cout << " metadata list list metadata info\n"; + cout << " mdlog list list metadata log\n"; + cout << " mdlog trim trim metadata log (use start-date, end-date or\n"; + cout << " start-marker, end-marker)\n"; ++ cout << " mdlog status read metadata log status\n"; + cout << " bilog list list bucket index log\n"; + cout << " bilog trim trim bucket index log (use start-marker, end-marker)\n"; + cout << " datalog list list data log\n"; + cout << " datalog trim trim data log\n"; ++ cout << " datalog status read data log status\n"; + cout << " opstate list list stateful operations entries (use client_id,\n"; + cout << " op_id, object)\n"; + cout << " opstate set set state on an entry (use client_id, op_id, object, state)\n"; + cout << " opstate renew renew state on an entry (use client_id, op_id, object)\n"; + cout << " opstate rm remove entry (use client_id, op_id, object)\n"; + cout << " replicalog get get replica metadata log entry\n"; + cout << " replicalog update update replica metadata log entry\n"; + cout << " replicalog delete delete replica metadata log entry\n"; + cout << " orphans find init and run search for leaked rados objects\n"; + cout << " orphans finish clean up search for leaked rados objects\n"; + cout << "options:\n"; + cout << " --tenant= tenant name\n"; + cout << " --uid= user id\n"; + cout << " --subuser= subuser name\n"; + cout << " --access-key= S3 access key\n"; + cout << " --email=\n"; + cout << " --secret/--secret-key=\n"; + cout << " specify secret key\n"; + cout << " --gen-access-key generate random access key (for S3)\n"; + cout << " --gen-secret generate random secret key\n"; + cout << " --key-type= key type, options are: swift, s3\n"; + cout << " --temp-url-key[-2]= temp url key\n"; + cout << " --access= Set access permissions for sub-user, should be one\n"; + cout << " of read, write, readwrite, full\n"; + cout << " --display-name=\n"; + cout << " --max_buckets max number of buckets for a user\n"; + cout << " --system set the system flag on the user\n"; + cout << " --bucket=\n"; + cout << " --pool=\n"; + cout << " --object=\n"; + cout << " --date=\n"; + cout << " --start-date=\n"; + cout << " --end-date=\n"; + cout << " --bucket-id=\n"; + cout << " --shard-id= optional for mdlog list\n"; + cout << " required for: \n"; + cout << " mdlog trim\n"; + cout << " replica mdlog get/delete\n"; + cout << " replica datalog get/delete\n"; + cout << " --metadata-key= key to retrieve metadata from with metadata get\n"; - cout << " --rgw-region= region in which radosgw is running\n"; ++ cout << " --remote= remote to pull period\n"; ++ cout << " --parent= parent period id\n"; ++ cout << " --period= period id\n"; ++ cout << " --epoch= period epoch\n"; ++ cout << " --commit commit the period during 'period update'\n"; ++ cout << " --master set as master\n"; ++ cout << " --master-url master url\n"; ++ cout << " --master-zonegroup= master zonegroup id\n"; ++ cout << " --master-zone= master zone id\n"; ++ cout << " --rgw-realm= realm name\n"; ++ cout << " --realm-id= realm id\n"; ++ cout << " --realm-new-name= realm new name\n"; ++ cout << " --rgw-zonegroup= zonegroup name\n"; + cout << " --rgw-zone= zone in which radosgw is running\n"; ++ cout << " --zone-new-name= zone new name\n"; ++ cout << " --default set entity (realm, zonegroup, zone) as default\n"; ++ cout << " --endpoints= zone endpoints\n"; + cout << " --fix besides checking bucket index, will also fix it\n"; + cout << " --check-objects bucket check: rebuilds bucket index according to\n"; + cout << " actual objects state\n"; + cout << " --format= specify output format for certain operations: xml,\n"; + cout << " json\n"; + cout << " --purge-data when specified, user removal will also purge all the\n"; + cout << " user data\n"; + cout << " --purge-keys when specified, subuser removal will also purge all the\n"; + cout << " subuser keys\n"; + cout << " --purge-objects remove a bucket's objects before deleting it\n"; + cout << " (NOTE: required to delete a non-empty bucket)\n"; + cout << " --sync-stats option to 'user stats', update user stats with current\n"; + cout << " stats reported by user's buckets indexes\n"; + cout << " --show-log-entries= enable/disable dump of log entries on log show\n"; + cout << " --show-log-sum= enable/disable dump of log summation on log show\n"; + cout << " --skip-zero-entries log show only dumps entries that don't have zero value\n"; + cout << " in one of the numeric field\n"; + cout << " --infile= specify a file to read in when setting data\n"; + cout << " --state= specify a state for the opstate set command\n"; + cout << " --replica-log-type replica log type (metadata, data, bucket), required for\n"; + cout << " replica log operations\n"; + cout << " --categories= comma separated list of categories, used in usage show\n"; + cout << " --caps= list of caps (e.g., \"usage=read, write; user=read\"\n"; + cout << " --yes-i-really-mean-it required for certain operations\n"; + cout << " --reset-regions reset regionmap when regionmap update"; + cout << "\n"; + cout << " := \"YYYY-MM-DD[ hh:mm:ss]\"\n"; + cout << "\nQuota options:\n"; + cout << " --bucket specified bucket for quota command\n"; + cout << " --max-objects specify max objects (negative value to disable)\n"; + cout << " --max-size specify max size (in bytes, negative value to disable)\n"; + cout << " --quota-scope scope of quota (bucket, user)\n"; + cout << "\nOrphans search options:\n"; + cout << " --pool data pool to scan for leaked rados objects in\n"; + cout << " --num-shards num of shards to use for keeping the temporary scan info\n"; + cout << "\n"; generic_client_usage(); } diff --cc src/rgw/rgw_civetweb_frontend.cc index 00000000000,cb320140157..e5c1b18d0cf mode 000000,100644..100644 --- a/src/rgw/rgw_civetweb_frontend.cc +++ b/src/rgw/rgw_civetweb_frontend.cc @@@ -1,0 -1,67 +1,70 @@@ + // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + // vim: ts=8 sw=2 smarttab + + #include "rgw_frontend.h" + + #define dout_subsys ceph_subsys_rgw + + static int civetweb_callback(struct mg_connection* conn) { + struct mg_request_info* req_info = mg_get_request_info(conn); - RGWProcessEnv* pe = static_cast(req_info->user_data); ++ RGWMongooseEnv* pe = static_cast(req_info->user_data); + RGWRados* store = pe->store; + RGWREST* rest = pe->rest; + OpsLogSocket* olog = pe->olog; + - RGWRequest* req = new RGWRequest(store->get_new_req_id()); ++ RGWRequest req(store->get_new_req_id()); + RGWMongoose client_io(conn, pe->port); + - int ret = process_request(store, rest, req, &client_io, olog); - if (ret < 0) { - /* we don't really care about return code */ - dout(20) << "process_request() returned " << ret << dendl; - } ++ { ++ // hold a read lock over access to pe->store for reconfiguration ++ RWLock::RLocker lock(pe->mutex); + - delete req; ++ int ret = process_request(pe->store, rest, &req, &client_io, olog); ++ if (ret < 0) { ++ /* we don't really care about return code */ ++ dout(20) << "process_request() returned " << ret << dendl; ++ } ++ } + + // Mark as processed + return 1; + } + + int RGWMongooseFrontend::run() { + char thread_pool_buf[32]; + snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d", + (int)g_conf->rgw_thread_pool_size); + string port_str; + map conf_map = conf->get_config_map(); + conf->get_val("port", "80", &port_str); + conf_map.erase("port"); + conf_map["listening_ports"] = port_str; + set_conf_default(conf_map, "enable_keep_alive", "yes"); + set_conf_default(conf_map, "num_threads", thread_pool_buf); + set_conf_default(conf_map, "decode_url", "no"); + + const char *options[conf_map.size() * 2 + 1]; + int i = 0; + for (map::iterator iter = conf_map.begin(); + iter != conf_map.end(); ++iter) { + options[i] = iter->first.c_str(); + options[i + 1] = iter->second.c_str(); + dout(20)<< "civetweb config: " << options[i] << ": " + << (options[i + 1] ? options[i + 1] : "") << dendl; + i += 2; + } + options[i] = NULL; + + struct mg_callbacks cb; + memset((void *)&cb, 0, sizeof(cb)); + cb.begin_request = civetweb_callback; + cb.log_message = rgw_civetweb_log_callback; + cb.log_access = rgw_civetweb_log_access_callback; + ctx = mg_start(&cb, &env, (const char **)&options); + + if (!ctx) { + return -EIO; + } + + return 0; + } /* RGWMongooseFrontend::run */ diff --cc src/rgw/rgw_common.h index cb164ef29da,628fd26b4ed..3cc3c4b64c9 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@@ -292,10 -290,8 +293,9 @@@ class RGWHTTPArg } /** parse the received arguments */ int parse(); + void append(const string& name, const string& val); /** Get the value for a specific argument parameter */ string& get(const string& name, bool *exists = NULL); - string& get(const char *name, bool *exists = NULL); int get_bool(const string& name, bool *val, bool *exists); int get_bool(const char *name, bool *val, bool *exists); void get_bool(const char *name, bool *val, bool def_val); @@@ -1074,88 -1081,87 +1087,89 @@@ struct req_init_state string src_bucket; }; + /* XXX why don't RGWRequest (or descendants) hold this state? */ + class RGWRequest; + /** Store all the state necessary to complete and respond to an HTTP request*/ struct req_state { - CephContext *cct; - RGWClientIO *cio; - http_op op; - bool content_started; - int format; - ceph::Formatter *formatter; - string decoded_uri; - string relative_uri; - const char *length; - int64_t content_length; - map generic_attrs; - struct rgw_err err; - bool expect_cont; - bool header_ended; - uint64_t obj_size; - bool enable_ops_log; - bool enable_usage_log; - uint8_t defer_to_bucket_acls; - uint32_t perm_mask; - utime_t header_time; - - /* Set once when url_bucket is parsed and not violated thereafter. */ - string bucket_tenant; - string bucket_name; - - rgw_bucket bucket; - rgw_obj_key object; - string src_tenant_name; - string src_bucket_name; - rgw_obj_key src_object; - ACLOwner bucket_owner; - ACLOwner owner; - - string zonegroup_name; - string zonegroup_endpoint; - string bucket_instance_id; - int bucket_instance_shard_id; - - string redirect; - - RGWBucketInfo bucket_info; - map bucket_attrs; - bool bucket_exists; - - bool has_bad_meta; - - RGWUserInfo user; - RGWAccessControlPolicy *bucket_acl; - RGWAccessControlPolicy *object_acl; - - bool system_request; - - string canned_acl; - bool has_acl_header; - const char *http_auth; - bool local_source; /* source is local */ - - int prot_flags; - - const char *os_auth_token; - string swift_user; - string swift_groups; - - utime_t time; - - void *obj_ctx; - - string dialect; - - string req_id; - - string trans_id; - - string host_id; - - req_info info; - req_init_state init_state; - - req_state(CephContext *_cct, class RGWEnv *e); - ~req_state(); + CephContext *cct; + RGWClientIO *cio; + RGWRequest *req; /// XXX: re-remove?? + http_op op; + bool content_started; + int format; + ceph::Formatter *formatter; + string decoded_uri; + string relative_uri; + const char *length; + int64_t content_length; + map generic_attrs; + struct rgw_err err; + bool expect_cont; + bool header_ended; + uint64_t obj_size; + bool enable_ops_log; + bool enable_usage_log; + uint8_t defer_to_bucket_acls; + uint32_t perm_mask; + utime_t header_time; + + /* Set once when url_bucket is parsed and not violated thereafter. */ + string bucket_tenant; + string bucket_name; + + rgw_bucket bucket; + rgw_obj_key object; + string src_tenant_name; + string src_bucket_name; + rgw_obj_key src_object; + ACLOwner bucket_owner; + ACLOwner owner; + - string region_endpoint; ++ string zonegroup_name; ++ string zonegroup_endpoint; + string bucket_instance_id; ++ int bucket_instance_shard_id; + + string redirect; + + RGWBucketInfo bucket_info; + map bucket_attrs; + bool bucket_exists; + + bool has_bad_meta; + + RGWUserInfo *user; + + RGWAccessControlPolicy *bucket_acl; + RGWAccessControlPolicy *object_acl; + + bool system_request; + + string canned_acl; + bool has_acl_header; + const char *http_auth; + bool local_source; /* source is local */ + + int prot_flags; + + const char *os_auth_token; + string swift_user; + string swift_groups; + + string host_id; + + req_info info; + req_init_state init_state; + + utime_t time; + void *obj_ctx; + string dialect; + string req_id; + string trans_id; + + req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u); + ~req_state(); }; /** Store basic data on an object */ diff --cc src/rgw/rgw_frontend.h index 00000000000,11497d4b0d0..928a03b8fe3 mode 000000,100644..100644 --- a/src/rgw/rgw_frontend.h +++ b/src/rgw/rgw_frontend.h @@@ -1,0 -1,167 +1,224 @@@ + // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + // vim: ts=8 sw=2 smarttab + + #ifndef RGW_FRONTEND_H + #define RGW_FRONTEND_H + + #include "rgw_request.h" + #include "rgw_process.h" ++#include "rgw_realm_reloader.h" + + #include "rgw_civetweb.h" + #include "rgw_civetweb_log.h" + #include "civetweb/civetweb.h" + + #define dout_subsys ceph_subsys_rgw + + class RGWFrontendConfig { + string config; + map config_map; + int parse_config(const string& config, map& config_map); + string framework; + public: + RGWFrontendConfig(const string& _conf) : config(_conf) {} + int init() { + int ret = parse_config(config, config_map); + if (ret < 0) + return ret; + return 0; + } + bool get_val(const string& key, const string& def_val, string *out); + bool get_val(const string& key, int def_val, int *out); + + map& get_config_map() { return config_map; } + + string get_framework() { return framework; } + }; + + class RGWFrontend { + public: + virtual ~RGWFrontend() {} + + virtual int init() = 0; + + virtual int run() = 0; + virtual void stop() = 0; + virtual void join() = 0; ++ ++ virtual void pause_for_new_config() = 0; ++ virtual void unpause_with_new_config(RGWRados *store) = 0; ++}; ++ ++struct RGWMongooseEnv : public RGWProcessEnv { ++ // every request holds a read lock, so we need to prioritize write locks to ++ // avoid starving pause_for_new_config() ++ static constexpr bool prioritize_write = true; ++ RWLock mutex; ++ RGWMongooseEnv(const RGWProcessEnv &env) ++ : RGWProcessEnv(env), ++ mutex("RGWMongooseFrontend", false, true, prioritize_write) {} + }; + + class RGWMongooseFrontend : public RGWFrontend { + RGWFrontendConfig* conf; + struct mg_context* ctx; - RGWProcessEnv env; ++ RGWMongooseEnv env; + + void set_conf_default(map& m, const string& key, + const string& def_val) { + if (m.find(key) == m.end()) { + m[key] = def_val; + } + } + + public: + RGWMongooseFrontend(RGWProcessEnv& pe, RGWFrontendConfig* _conf) + : conf(_conf), ctx(nullptr), env(pe) { + } + + int init() { + return 0; + } + + int run(); + + void stop() { + if (ctx) { + mg_stop(ctx); + } + } + + void join() { + } ++ ++ void pause_for_new_config() override { ++ // block callbacks until unpause ++ env.mutex.get_write(); ++ } ++ ++ void unpause_with_new_config(RGWRados *store) override { ++ env.store = store; ++ // unpause callbacks ++ env.mutex.put_write(); ++ } + }; /* RGWMongooseFrontend */ + + class RGWProcessFrontend : public RGWFrontend { + protected: + RGWFrontendConfig* conf; + RGWProcess* pprocess; + RGWProcessEnv env; + RGWProcessControlThread* thread; + + public: + RGWProcessFrontend(RGWProcessEnv& pe, RGWFrontendConfig* _conf) + : conf(_conf), pprocess(nullptr), env(pe), thread(nullptr) { + } + + ~RGWProcessFrontend() { + delete thread; + delete pprocess; + } + + int run() { + assert(pprocess); /* should have initialized by init() */ + thread = new RGWProcessControlThread(pprocess); + thread->create("rgw_frontend"); + return 0; + } + + void stop(); + + void join() { + thread->join(); + } ++ ++ void pause_for_new_config() override { ++ pprocess->pause(); ++ } ++ ++ void unpause_with_new_config(RGWRados *store) override { ++ env.store = store; ++ pprocess->unpause_with_new_config(store); ++ } + }; /* RGWProcessFrontend */ + + class RGWFCGXFrontend : public RGWProcessFrontend { + public: + RGWFCGXFrontend(RGWProcessEnv& pe, RGWFrontendConfig* _conf) + : RGWProcessFrontend(pe, _conf) {} + + int init() { + pprocess = new RGWFCGXProcess(g_ceph_context, &env, + g_conf->rgw_thread_pool_size, conf); + return 0; + } + }; /* RGWFCGXFrontend */ + + class RGWLoadGenFrontend : public RGWProcessFrontend { + public: + RGWLoadGenFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) + : RGWProcessFrontend(pe, _conf) {} + + int init() { + int num_threads; + conf->get_val("num_threads", g_conf->rgw_thread_pool_size, &num_threads); + RGWLoadGenProcess *pp = new RGWLoadGenProcess(g_ceph_context, &env, + num_threads, conf); + + pprocess = pp; + + string uid_str; + conf->get_val("uid", "", &uid_str); + if (uid_str.empty()) { + derr << "ERROR: uid param must be specified for loadgen frontend" + << dendl; + return EINVAL; + } + + rgw_user uid(uid_str); + + RGWUserInfo user_info; + int ret = rgw_get_user_info_by_uid(env.store, uid, user_info, NULL); + if (ret < 0) { + derr << "ERROR: failed reading user info: uid=" << uid << " ret=" + << ret << dendl; + return ret; + } + + map::iterator aiter = user_info.access_keys.begin(); + if (aiter == user_info.access_keys.end()) { + derr << "ERROR: user has no S3 access keys set" << dendl; + return -EINVAL; + } + + pp->set_access_key(aiter->second); + + return 0; + } + }; /* RGWLoadGenFrontend */ + ++// FrontendPauser implementation for RGWRealmReloader ++class RGWFrontendPauser : public RGWRealmReloader::Pauser { ++ std::list &frontends; ++ RGWRealmReloader::Pauser* pauser; ++ public: ++ RGWFrontendPauser(std::list &frontends, ++ RGWRealmReloader::Pauser* pauser = nullptr) ++ : frontends(frontends), pauser(pauser) {} ++ ++ void pause() override { ++ for (auto frontend : frontends) ++ frontend->pause_for_new_config(); ++ if (pauser) ++ pauser->pause(); ++ } ++ void resume(RGWRados *store) { ++ for (auto frontend : frontends) ++ frontend->unpause_with_new_config(store); ++ if (pauser) ++ pauser->resume(store); ++ } ++}; ++ + #endif /* RGW_FRONTEND_H */ diff --cc src/rgw/rgw_lib.h index 00000000000,9cea8e40242..bd59f6072e5 mode 000000,100644..100644 --- a/src/rgw/rgw_lib.h +++ b/src/rgw/rgw_lib.h @@@ -1,0 -1,197 +1,199 @@@ + // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + // vim: ts=8 sw=2 smarttab + #ifndef RGW_LIB_H + #define RGW_LIB_H + + #include + #include "include/unordered_map.h" + #include "rgw_common.h" + #include "rgw_client_io.h" + #include "rgw_rest.h" + #include "rgw_request.h" + #include "rgw_frontend.h" + #include "rgw_process.h" + #include "rgw_rest_s3.h" // RGW_Auth_S3 + + class OpsLogSocket; + + namespace rgw { + + class RGWLibFrontendConfig; + class RGWLibFrontend; + + class RGWLib { + RGWFrontendConfig* fec; + RGWLibFrontend* fe; + OpsLogSocket* olog; + RGWREST rest; // XXX needed for RGWProcessEnv + RGWProcessEnv env; + RGWRados* store; + + public: + RGWLib() : fec(nullptr), fe(nullptr), olog(nullptr), store(nullptr) + {} + ~RGWLib() {} + + RGWRados* get_store() { return store; } + + RGWLibFrontend* get_fe() { return fe; } + + int init(); + int init(vector& args); + int stop(); + }; + + extern RGWLib rgwlib; + + /* request interface */ + + class RGWLibIO : public RGWClientIO + { + RGWUserInfo user_info; + public: + RGWLibIO() { + get_env().set("HTTP_HOST", ""); + } + RGWLibIO(const RGWUserInfo &_user_info) + : user_info(_user_info) {} + + virtual void init_env(CephContext *cct) {} + + const RGWUserInfo& get_user() { + return user_info; + } + + int set_uid(RGWRados* store, const rgw_user& uid); + + int write_data(const char *buf, int len); + int read_data(char *buf, int len); + int send_status(int status, const char *status_name); + int send_100_continue(); + int complete_header(); + int send_content_length(uint64_t len); + + int complete_request() { /* XXX */ + return 0; + }; + + }; /* RGWLibIO */ + + /* XXX */ + class RGWRESTMgr_Lib : public RGWRESTMgr { + public: + RGWRESTMgr_Lib() {} + virtual ~RGWRESTMgr_Lib() {} + }; /* RGWRESTMgr_Lib */ + + /* XXX */ + class RGWHandler_Lib : public RGWHandler { + friend class RGWRESTMgr_Lib; + public: + + virtual int authorize(); + + RGWHandler_Lib() {} + virtual ~RGWHandler_Lib() {} + static int init_from_header(struct req_state *s); + }; /* RGWHandler_Lib */ + + class RGWLibRequest : public RGWRequest, + public RGWHandler_Lib { + public: + CephContext* cct; + RGWUserInfo* user; + + /* unambiguiously return req_state */ + inline struct req_state* get_state() { return this->RGWRequest::s; } + + RGWLibRequest(CephContext* _cct, RGWUserInfo* _user) + : RGWRequest(0), cct(_cct), user(_user) + {} + + RGWUserInfo* get_user() { return user; } + + virtual int postauth_init() { return 0; } + + /* descendant equivalent of *REST*::init_from_header(...): + * prepare request for execute()--should mean, fixup URI-alikes + * and any other expected stat vars in local req_state, for + * now */ + virtual int header_init() = 0; + + /* descendant initializer responsible to call RGWOp::init()--which + * descendants are required to inherit */ + virtual int op_init() = 0; + ++ using RGWHandler::init; ++ + int init(const RGWEnv& rgw_env, RGWObjectCtx* rados_ctx, + RGWLibIO* io, struct req_state* _s) { + + RGWRequest::init_state(_s); + RGWHandler::init(rados_ctx->store, _s, io); + + /* fixup _s->req */ + _s->req = this; + + log_init(); + + get_state()->obj_ctx = rados_ctx; + get_state()->req_id = store->unique_id(id); + get_state()->trans_id = store->unique_trans_id(id); + + log_format(_s, "initializing for trans_id = %s", + get_state()->trans_id.c_str()); + + int ret = header_init(); + if (ret == 0) { + ret = init_from_header(_s); + } + return ret; + } + + virtual bool only_bucket() = 0; + + virtual int read_permissions(RGWOp *op); + + }; /* RGWLibRequest */ + + class RGWLibContinuedReq : public RGWLibRequest { + RGWLibIO io_ctx; + struct req_state rstate; + RGWObjectCtx rados_ctx; + public: + + RGWLibContinuedReq(CephContext* _cct, RGWUserInfo* _user) + : RGWLibRequest(_cct, _user), io_ctx(), + rstate(_cct, &io_ctx.get_env(), _user), rados_ctx(rgwlib.get_store(), + &rstate) + { + io_ctx.init(_cct); + + RGWRequest::init_state(&rstate); + RGWHandler::init(rados_ctx.store, &rstate, &io_ctx); + + /* fixup _s->req */ + get_state()->req = this; + + log_init(); + + get_state()->obj_ctx = &rados_ctx; + get_state()->req_id = store->unique_id(id); + get_state()->trans_id = store->unique_trans_id(id); + + log_format(get_state(), "initializing for trans_id = %s", + get_state()->trans_id.c_str()); + } + + inline RGWRados* get_store() { return store; } + + virtual int execute() final { abort(); } + virtual int exec_start() = 0; + virtual int exec_continue() = 0; + virtual int exec_finish() = 0; + + }; /* RGWLibContinuedReq */ + + } /* namespace rgw */ + + #endif /* RGW_LIB_H */ diff --cc src/rgw/rgw_main.cc index d6bbaf9bd22,6a2c59e23a5..8f44299db05 --- a/src/rgw/rgw_main.cc +++ b/src/rgw/rgw_main.cc @@@ -13,16 -13,7 +13,9 @@@ #include +#include + #include "acconfig.h" - #ifdef FASTCGI_INCLUDE_DIR - # include "fastcgi/fcgiapp.h" - #else - # include "fcgiapp.h" - #endif - - #include "rgw_fcgi.h" #include "common/ceph_argparse.h" #include "global/global_init.h" @@@ -38,11 -26,7 +28,9 @@@ #include "include/str_list.h" #include "rgw_common.h" #include "rgw_rados.h" - #include "rgw_acl.h" #include "rgw_user.h" - #include "rgw_op.h" +#include "rgw_period_pusher.h" +#include "rgw_realm_reloader.h" #include "rgw_rest.h" #include "rgw_rest_s3.h" #include "rgw_rest_swift.h" @@@ -842,293 -169,6 +174,9 @@@ static RGWRESTMgr *set_logging(RGWRESTM return mgr; } - - int RGWFrontendConfig::parse_config(const string& config, map& config_map) - { - list config_list; - get_str_list(config, " ", config_list); - - list::iterator iter; - for (iter = config_list.begin(); iter != config_list.end(); ++iter) { - string& entry = *iter; - string key; - string val; - - if (framework.empty()) { - framework = entry; - dout(0) << "framework: " << framework << dendl; - continue; - } - - ssize_t pos = entry.find('='); - if (pos < 0) { - dout(0) << "framework conf key: " << entry << dendl; - config_map[entry] = ""; - continue; - } - - int ret = parse_key_value(entry, key, val); - if (ret < 0) { - cerr << "ERROR: can't parse " << entry << std::endl; - return ret; - } - - dout(0) << "framework conf key: " << key << ", val: " << val << dendl; - config_map[key] = val; - } - - return 0; - } - - - bool RGWFrontendConfig::get_val(const string& key, const string& def_val, string *out) - { - map::iterator iter = config_map.find(key); - if (iter == config_map.end()) { - *out = def_val; - return false; - } - - *out = iter->second; - return true; - } - - - bool RGWFrontendConfig::get_val(const string& key, int def_val, int *out) - { - string str; - bool found = get_val(key, "", &str); - if (!found) { - *out = def_val; - return false; - } - string err; - *out = strict_strtol(str.c_str(), 10, &err); - if (!err.empty()) { - cerr << "error parsing int: " << str << ": " << err << std::endl; - return -EINVAL; - } - return 0; - } - - class RGWFrontend { - public: - virtual ~RGWFrontend() {} - - virtual int init() = 0; - - virtual int run() = 0; - virtual void stop() = 0; - virtual void join() = 0; - - virtual void pause_for_new_config() = 0; - virtual void unpause_with_new_config(RGWRados *store) = 0; - }; - - class RGWProcessControlThread : public Thread { - RGWProcess *pprocess; - public: - explicit RGWProcessControlThread(RGWProcess *_pprocess) : pprocess(_pprocess) {} - - void *entry() { - pprocess->run(); - return NULL; - } - }; - - class RGWProcessFrontend : public RGWFrontend { - protected: - RGWFrontendConfig *conf; - RGWProcess *pprocess; - RGWProcessEnv env; - RGWProcessControlThread *thread; - - public: - RGWProcessFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : conf(_conf), pprocess(NULL), env(pe), thread(NULL) { - } - - ~RGWProcessFrontend() { - delete thread; - delete pprocess; - } - - int run() { - assert(pprocess); /* should have initialized by init() */ - thread = new RGWProcessControlThread(pprocess); - thread->create("rgw_frontend"); - return 0; - } - - void stop() { - pprocess->close_fd(); - thread->kill(SIGUSR1); - } - - void join() { - thread->join(); - } - - void pause_for_new_config() override { - pprocess->pause(); - } - - void unpause_with_new_config(RGWRados *store) override { - env.store = store; - pprocess->unpause_with_new_config(store); - } - }; - - class RGWFCGXFrontend : public RGWProcessFrontend { - public: - RGWFCGXFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : RGWProcessFrontend(pe, _conf) {} - - int init() { - pprocess = new RGWFCGXProcess(g_ceph_context, &env, g_conf->rgw_thread_pool_size, conf); - return 0; - } - }; - - class RGWLoadGenFrontend : public RGWProcessFrontend { - public: - RGWLoadGenFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : RGWProcessFrontend(pe, _conf) {} - - int init() { - int num_threads; - conf->get_val("num_threads", g_conf->rgw_thread_pool_size, &num_threads); - RGWLoadGenProcess *pp = new RGWLoadGenProcess(g_ceph_context, &env, num_threads, conf); - - pprocess = pp; - - string uid_str; - conf->get_val("uid", "", &uid_str); - if (uid_str.empty()) { - derr << "ERROR: uid param must be specified for loadgen frontend" << dendl; - return EINVAL; - } - - rgw_user uid(uid_str); - - RGWUserInfo user_info; - int ret = rgw_get_user_info_by_uid(env.store, uid, user_info, NULL); - if (ret < 0) { - derr << "ERROR: failed reading user info: uid=" << uid << " ret=" << ret << dendl; - return ret; - } - - map::iterator aiter = user_info.access_keys.begin(); - if (aiter == user_info.access_keys.end()) { - derr << "ERROR: user has no S3 access keys set" << dendl; - return -EINVAL; - } - - pp->set_access_key(aiter->second); - - return 0; - } - }; - - class RGWMongooseFrontend : public RGWFrontend { - RGWFrontendConfig *conf; - struct mg_context *ctx; - RGWMongooseEnv env; - - void set_conf_default(map& m, const string& key, const string& def_val) { - if (m.find(key) == m.end()) { - m[key] = def_val; - } - } - - public: - RGWMongooseFrontend(RGWProcessEnv& pe, RGWFrontendConfig *_conf) : conf(_conf), ctx(NULL), env(pe) { - } - - int init() { - return 0; - } - - int run() { - char thread_pool_buf[32]; - snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d", (int)g_conf->rgw_thread_pool_size); - string port_str; - map conf_map = conf->get_config_map(); - conf->get_val("port", "80", &port_str); - conf_map.erase("port"); - conf_map["listening_ports"] = port_str; - set_conf_default(conf_map, "enable_keep_alive", "yes"); - set_conf_default(conf_map, "num_threads", thread_pool_buf); - set_conf_default(conf_map, "decode_url", "no"); - - const char *options[conf_map.size() * 2 + 1]; - int i = 0; - for (map::iterator iter = conf_map.begin(); iter != conf_map.end(); ++iter) { - options[i] = iter->first.c_str(); - options[i + 1] = iter->second.c_str(); - dout(20)<< "civetweb config: " << options[i] << ": " << (options[i + 1] ? options[i + 1] : "") << dendl; - i += 2; - } - options[i] = NULL; - - struct mg_callbacks cb; - memset((void *)&cb, 0, sizeof(cb)); - cb.begin_request = civetweb_callback; - cb.log_message = rgw_civetweb_log_callback; - cb.log_access = rgw_civetweb_log_access_callback; - ctx = mg_start(&cb, &env, (const char **)&options); - - if (!ctx) { - return -EIO; - } - - return 0; - } - - void stop() { - if (ctx) { - mg_stop(ctx); - } - } - - void join() { - } - - void pause_for_new_config() override { - // block callbacks until unpause - env.mutex.get_write(); - } - - void unpause_with_new_config(RGWRados *store) override { - env.store = store; - // unpause callbacks - env.mutex.put_write(); - } - }; - - // FrontendPauser implementation for RGWRealmReloader - class RGWFrontendPauser : public RGWRealmReloader::Pauser { - std::list &frontends; - RGWRealmReloader::Pauser* pauser; - public: - RGWFrontendPauser(std::list &frontends, - RGWRealmReloader::Pauser* pauser = nullptr) - : frontends(frontends), pauser(pauser) {} - - void pause() override { - for (auto frontend : frontends) - frontend->pause_for_new_config(); - if (pauser) - pauser->pause(); - } - void resume(RGWRados *store) { - for (auto frontend : frontends) - frontend->unpause_with_new_config(store); - if (pauser) - pauser->resume(store); - } - }; - +void intrusive_ptr_add_ref(CephContext* cct) { cct->get(); } +void intrusive_ptr_release(CephContext* cct) { cct->put(); } + /* * start up the RADOS connection and then handle HTTP messages as they come in */ diff --cc src/rgw/rgw_op.cc index 12cf50567a7,df884086ec0..f3c95ea976c --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@@ -1709,11 -1641,13 +1675,13 @@@ static int forward_request_to_master(st ldout(s->cct, 0) << "rest connection is invalid" << dendl; return -EINVAL; } - ldout(s->cct, 0) << "sending create_bucket request to master region" << dendl; + ldout(s->cct, 0) << "sending create_bucket request to master zonegroup" << dendl; bufferlist response; - string uid_str = s->user.user_id.to_str(); + string uid_str = s->user->user_id.to_str(); #define MAX_REST_RESPONSE (128 * 1024) // we expect a very small response - int ret = store->rest_master_conn->forward(uid_str, s->info, objv, MAX_REST_RESPONSE, &in_data, &response); + int ret = store->rest_master_conn->forward(uid_str, s->info, objv, + MAX_REST_RESPONSE, &in_data, + &response); if (ret < 0) return ret; @@@ -1812,10 -1747,10 +1781,10 @@@ void RGWCreateBucket::execute( if (s->bucket_exists) { string selected_placement_rule; rgw_bucket bucket; - op_ret = store->select_bucket_placement(s->user, zonegroup_id, - op_ret = store->select_bucket_placement(*(s->user), region_name, - placement_rule, s->bucket_tenant, - s->bucket_name, bucket, - &selected_placement_rule); ++ op_ret = store->select_bucket_placement(*(s->user), zonegroup_id, + placement_rule, + s->bucket_tenant, s->bucket_name, + bucket, &selected_placement_rule); if (selected_placement_rule != s->bucket_info.placement_rule) { op_ret = -EEXIST; return; @@@ -1832,11 -1767,11 +1801,11 @@@ } s->bucket.tenant = s->bucket_tenant; /* ignored if bucket exists */ s->bucket.name = s->bucket_name; - op_ret = store->create_bucket(s->user, s->bucket, zonegroup_id, placement_rule, - op_ret = store->create_bucket(*(s->user), s->bucket, region_name, - placement_rule, attrs, info, pobjv, &ep_objv, - creation_time, pmaster_bucket, true); ++ op_ret = store->create_bucket(*(s->user), s->bucket, zonegroup_id, placement_rule, + attrs, info, pobjv, &ep_objv, creation_time, + pmaster_bucket, true); - /* continue if EEXIST and create_bucket will fail below. this way we can recover - * from a partial create by retrying it. */ + /* continue if EEXIST and create_bucket will fail below. this way we can + * recover from a partial create by retrying it. */ ldout(s->cct, 20) << "rgw_create_bucket returned ret=" << op_ret << " bucket=" << s->bucket << dendl; if (op_ret && op_ret != -EEXIST) @@@ -2699,8 -2546,9 +2589,8 @@@ void RGWPutMetadataAccount::execute( } rgw_get_request_metadata(s->cct, s->info, attrs, false); - rgw_get_user_attrs_by_uid(store, s->user->user_id, orig_attrs, - &acct_op_tracker); - prepare_add_del_attrs(orig_attrs, rmattr_names, attrs, rmattrs); + RGWUserInfo orig_uinfo; - rgw_get_user_info_by_uid(store, s->user.user_id, orig_uinfo, &acct_op_tracker); ++ rgw_get_user_info_by_uid(store, s->user->user_id, orig_uinfo, &acct_op_tracker); populate_with_generic_attrs(s, attrs); /* Handle the TempURL-related stuff. */ @@@ -2714,8 -2562,8 +2604,8 @@@ } /* XXX tenant needed? */ - op_ret = rgw_store_user_info(store, s->user, &orig_uinfo, - op_ret = rgw_store_user_attrs(store, s->user->user_id.id, attrs, &rmattrs, - &acct_op_tracker); ++ op_ret = rgw_store_user_info(store, *(s->user), &orig_uinfo, + &acct_op_tracker, 0, false, &attrs); if (op_ret < 0) { return; } diff --cc src/rgw/rgw_process.h index 00000000000,33bad85da90..0cb74150584 mode 000000,100644..100644 --- a/src/rgw/rgw_process.h +++ b/src/rgw/rgw_process.h @@@ -1,0 -1,170 +1,179 @@@ + // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + // vim: ts=8 sw=2 smarttab + + #ifndef RGW_PROCESS_H + #define RGW_PROCESS_H + + #include "rgw_common.h" + #include "rgw_rados.h" + #include "rgw_acl.h" + #include "rgw_user.h" + #include "rgw_op.h" + #include "rgw_rest.h" + + #include "common/WorkQueue.h" + #include "common/Throttle.h" + + #if !defined(dout_subsys) + #define dout_subsys ceph_subsys_rgw + #define def_dout_subsys + #endif + + #define SOCKET_BACKLOG 1024 + + extern void signal_shutdown(); + + struct RGWProcessEnv { + RGWRados *store; + RGWREST *rest; + OpsLogSocket *olog; + int port; + }; + + class RGWFrontendConfig; + + class RGWProcess { + deque m_req_queue; + protected: + CephContext *cct; + RGWRados* store; + OpsLogSocket* olog; + ThreadPool m_tp; + Throttle req_throttle; + RGWREST* rest; + RGWFrontendConfig* conf; + int sock_fd; + + struct RGWWQ : public ThreadPool::WorkQueue { + RGWProcess* process; + RGWWQ(RGWProcess* p, time_t timeout, time_t suicide_timeout, ThreadPool* tp) + : ThreadPool::WorkQueue("RGWWQ", timeout, suicide_timeout, + tp), process(p) {} + + bool _enqueue(RGWRequest* req) { + process->m_req_queue.push_back(req); + perfcounter->inc(l_rgw_qlen); + dout(20) << "enqueued request req=" << hex << req << dec << dendl; + _dump_queue(); + return true; + } + + void _dequeue(RGWRequest* req) { + assert(0); + } + + bool _empty() { + return process->m_req_queue.empty(); + } + + RGWRequest* _dequeue() { + if (process->m_req_queue.empty()) + return NULL; + RGWRequest *req = process->m_req_queue.front(); + process->m_req_queue.pop_front(); + dout(20) << "dequeued request req=" << hex << req << dec << dendl; + _dump_queue(); + perfcounter->inc(l_rgw_qlen, -1); + return req; + } + + using ThreadPool::WorkQueue::_process; + + void _process(RGWRequest *req, ThreadPool::TPHandle &) override { + perfcounter->inc(l_rgw_qactive); + process->handle_request(req); + process->req_throttle.put(1); + perfcounter->inc(l_rgw_qactive, -1); + } + + void _dump_queue(); + + void _clear() { + assert(process->m_req_queue.empty()); + } + } req_wq; + + public: + RGWProcess(CephContext* cct, RGWProcessEnv* pe, int num_threads, + RGWFrontendConfig* _conf) + : cct(cct), store(pe->store), olog(pe->olog), + m_tp(cct, "RGWProcess::m_tp", "tp_rgw_process", num_threads), + req_throttle(cct, "rgw_ops", num_threads * 2), + rest(pe->rest), conf(_conf), sock_fd(-1), + req_wq(this, g_conf->rgw_op_thread_timeout, + g_conf->rgw_op_thread_suicide_timeout, &m_tp) {} + + virtual ~RGWProcess() {} + + virtual void run() = 0; + virtual void handle_request(RGWRequest *req) = 0; + ++ void pause() { ++ m_tp.pause(); ++ } ++ ++ void unpause_with_new_config(RGWRados *store) { ++ this->store = store; ++ m_tp.unpause(); ++ } ++ + void close_fd() { + if (sock_fd >= 0) { + ::close(sock_fd); + sock_fd = -1; + } + } + }; /* RGWProcess */ + + class RGWFCGXProcess : public RGWProcess { + int max_connections; + public: + + /* have a bit more connections than threads so that requests are + * still accepted even if we're still processing older requests */ + RGWFCGXProcess(CephContext* cct, RGWProcessEnv* pe, int num_threads, + RGWFrontendConfig* _conf) + : RGWProcess(cct, pe, num_threads, _conf), + max_connections(num_threads + (num_threads >> 3)) + {} + + void run(); + void handle_request(RGWRequest* req); + }; + + class RGWProcessControlThread : public Thread { + RGWProcess *pprocess; + public: + RGWProcessControlThread(RGWProcess *_pprocess) : pprocess(_pprocess) {} + + void *entry() { + pprocess->run(); + return NULL; + } + }; + + class RGWLoadGenProcess : public RGWProcess { + RGWAccessKey access_key; + public: + RGWLoadGenProcess(CephContext* cct, RGWProcessEnv* pe, int num_threads, + RGWFrontendConfig* _conf) : + RGWProcess(cct, pe, num_threads, _conf) {} + void run(); + void checkpoint(); + void handle_request(RGWRequest* req); + void gen_request(const string& method, const string& resource, + int content_length, atomic_t* fail_flag); + + void set_access_key(RGWAccessKey& key) { access_key = key; } + }; + + /* process stream request */ + int process_request(RGWRados* store, RGWREST* rest, RGWRequest* req, + RGWStreamIO* client_io, OpsLogSocket* olog); + + #if defined(def_dout_subsys) + #undef def_dout_subsys + #undef dout_subsys + #endif + + #endif /* RGW_PROCESS_H */ diff --cc src/rgw/rgw_rados.h index 60d54c5b673,2478df2b204..4a9659346c5 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@@ -3038,9 -2449,7 +3038,9 @@@ public const char *if_match = NULL, const char *if_nomatch = NULL); CephContext *ctx(); + + bool is_canceled() { return canceled; } - }; + }; /* RGWPutObjProcessor */ struct put_obj_aio_info { void *handle; diff --cc src/rgw/rgw_rest_config.h index e0c1fd6fecb,143e4cb8705..fe7f0272b0c --- a/src/rgw/rgw_rest_config.h +++ b/src/rgw/rgw_rest_config.h @@@ -11,15 -11,15 +11,16 @@@ * Foundation. See file COPYING. * */ - #ifndef CEPH_RGW_REST_CONFIG_H - #define CEPH_RGW_REST_CONFIG_H + + #ifndef RGW_REST_CONFIG_H + #define RGW_REST_CONFIG_H -class RGWOp_RegionMap_Get : public RGWRESTOp { - RGWRegionMap regionmap; +class RGWOp_ZoneGroupMap_Get : public RGWRESTOp { + RGWZoneGroupMap zonegroup_map; + bool old_format; public: - RGWOp_RegionMap_Get() {} - ~RGWOp_RegionMap_Get() {} + RGWOp_ZoneGroupMap_Get(bool _old_format):old_format(_old_format) {} + ~RGWOp_ZoneGroupMap_Get() {} int verify_permission() { return 0; diff --cc src/rgw/rgw_rest_realm.cc index 2f45db99009,00000000000..176802b1d39 mode 100644,000000..100644 --- a/src/rgw/rgw_rest_realm.cc +++ b/src/rgw/rgw_rest_realm.cc @@@ -1,278 -1,0 +1,278 @@@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/errno.h" +#include "rgw_rest_realm.h" +#include "rgw_rest_s3.h" +#include "rgw_rest_config.h" + +#define dout_subsys ceph_subsys_rgw + +// reject 'period push' if we would have to fetch too many intermediate periods +static const uint32_t PERIOD_HISTORY_FETCH_MAX = 64; + +// base period op, shared between Get and Post +class RGWOp_Period_Base : public RGWRESTOp { + protected: + RGWPeriod period; + public: + int verify_permission() override { return 0; } + void send_response() override; +}; + +// reply with the period object on success +void RGWOp_Period_Base::send_response() +{ + set_req_state_err(s, http_ret); + dump_errno(s); + end_header(s); + + if (http_ret < 0) + return; + + encode_json("period", period, s->formatter); + flusher.flush(); +} + +// GET /admin/realm/period +class RGWOp_Period_Get : public RGWOp_Period_Base { + public: + void execute() override; + const string name() override { return "get_period"; } +}; + +void RGWOp_Period_Get::execute() +{ + string realm_id, realm_name, period_id; + epoch_t epoch = 0; + RESTArgs::get_string(s, "realm_id", realm_id, &realm_id); + RESTArgs::get_string(s, "realm_name", realm_name, &realm_name); + RESTArgs::get_string(s, "period_id", period_id, &period_id); + RESTArgs::get_uint32(s, "epoch", 0, &epoch); + + period.set_id(period_id); + period.set_epoch(epoch); + + http_ret = period.init(store->ctx(), store, realm_id, realm_name); + if (http_ret < 0) + ldout(store->ctx(), 5) << "failed to read period" << dendl; +} + +// POST /admin/realm/period +class RGWOp_Period_Post : public RGWOp_Period_Base { + public: + void execute() override; + const string name() override { return "post_period"; } +}; + +void RGWOp_Period_Post::execute() +{ + auto cct = store->ctx(); + + // initialize the period without reading from rados + period.init(cct, store, false); + + // decode the period from input +#define PERIOD_MAX_LEN 4096 + bool empty; + http_ret = rgw_rest_get_json_input(cct, s, period, PERIOD_MAX_LEN, &empty); + if (http_ret < 0) { + lderr(cct) << "failed to decode period" << dendl; + return; + } + + // require period.realm_id to match our realm + if (period.get_realm() != store->realm.get_id()) { + lderr(cct) << "period with realm id " << period.get_realm() + << " doesn't match current realm " << store->realm.get_id() << dendl; + http_ret = -EINVAL; + return; + } + + // load the realm and current period from rados; there may be a more recent + // period that we haven't restarted with yet. we also don't want to modify + // the objects in use by RGWRados + RGWRealm realm(period.get_realm()); + http_ret = realm.init(cct, store); + if (http_ret < 0) { + lderr(cct) << "failed to read current realm: " + << cpp_strerror(-http_ret) << dendl; + return; + } + + RGWPeriod current_period; + http_ret = current_period.init(cct, store, realm.get_id()); + if (http_ret < 0) { + lderr(cct) << "failed to read current period: " + << cpp_strerror(-http_ret) << dendl; + return; + } + + // if period id is empty, handle as 'period commit' + if (period.get_id().empty()) { + http_ret = period.commit(realm, current_period); + if (http_ret < 0) { + lderr(cct) << "master zone failed to commit period" << dendl; + } + return; + } + + // if it's not period commit, nobody is allowed to push to the master zone + if (period.get_master_zone() == store->get_zone_params().get_id()) { + ldout(cct, 10) << "master zone rejecting period id=" + << period.get_id() << " epoch=" << period.get_epoch() << dendl; + http_ret = -EINVAL; // XXX: error code + return; + } + + // write the period to rados + http_ret = period.store_info(false); + if (http_ret < 0) { + lderr(cct) << "failed to store period " << period.get_id() << dendl; + return; + } + + // decide whether we can set_current_period() or set_latest_epoch() + if (period.get_id() != current_period.get_id()) { + auto current_epoch = current_period.get_realm_epoch(); + // discard periods in the past + if (period.get_realm_epoch() < current_epoch) { + ldout(cct, 10) << "discarding period " << period.get_id() + << " with realm epoch " << period.get_realm_epoch() + << " older than current epoch " << current_epoch << dendl; + // return success to ack that we have this period + return; + } + // discard periods too far in the future + if (period.get_realm_epoch() > current_epoch + PERIOD_HISTORY_FETCH_MAX) { + lderr(cct) << "discarding period " << period.get_id() + << " with realm epoch " << period.get_realm_epoch() << " too far in " + "the future from current epoch " << current_epoch << dendl; + http_ret = -ENOENT; // XXX: error code + return; + } + // attach a copy of the period into the period history + auto cursor = store->period_history->attach(RGWPeriod{period}); + if (!cursor) { + // we're missing some history between the new period and current_period + http_ret = cursor.get_error(); + lderr(cct) << "failed to collect the periods between current period " + << current_period.get_id() << " (realm epoch " << current_epoch + << ") and the new period " << period.get_id() + << " (realm epoch " << period.get_realm_epoch() + << "): " << cpp_strerror(-http_ret) << dendl; + return; + } + if (cursor.has_next()) { + // don't switch if we have a newer period in our history + ldout(cct, 4) << "attached period " << period.get_id() + << " to history, but the history contains newer periods" << dendl; + return; + } + // set as current period + http_ret = realm.set_current_period(period); + if (http_ret < 0) { + lderr(cct) << "failed to update realm's current period" << dendl; + return; + } + ldout(cct, 4) << "period " << period.get_id() + << " is newer than current period " << current_period.get_id() + << ", updating realm's current period and notifying zone" << dendl; + realm.notify_new_period(period); + return; + } + + if (period.get_epoch() <= current_period.get_epoch()) { + lderr(cct) << "period epoch " << period.get_epoch() << " is not newer " + "than current epoch " << current_period.get_epoch() + << ", discarding update" << dendl; + return; + } + // set as latest epoch + http_ret = period.set_latest_epoch(period.get_epoch()); + if (http_ret < 0) { + lderr(cct) << "failed to set latest epoch" << dendl; + return; + } + // reflect the period into our local objects + http_ret = period.reflect(); + if (http_ret < 0) { + lderr(cct) << "failed to update local objects: " + << cpp_strerror(-http_ret) << dendl; + return; + } + ldout(cct, 4) << "period epoch " << period.get_epoch() + << " is newer than current epoch " << current_period.get_epoch() + << ", updating period's latest epoch and notifying zone" << dendl; + realm.notify_new_period(period); + // update the period history + store->period_history->insert(RGWPeriod{period}); +} + +class RGWHandler_Period : public RGWHandler_Auth_S3 { + protected: + RGWOp *op_get() override { return new RGWOp_Period_Get; } + RGWOp *op_post() override { return new RGWOp_Period_Post; } +}; + +class RGWRESTMgr_Period : public RGWRESTMgr { + public: - RGWHandler* get_handler(struct req_state*) override { ++ RGWHandler_REST* get_handler(struct req_state*) override { + return new RGWHandler_Period; + } +}; + + +// GET /admin/realm +class RGWOp_Realm_Get : public RGWRESTOp { + std::unique_ptr realm; +public: + int verify_permission() override { return 0; } + void execute() override; + void send_response() override; + const string name() { return "get_realm"; } +}; + +void RGWOp_Realm_Get::execute() +{ + string id; + RESTArgs::get_string(s, "id", id, &id); + string name; + RESTArgs::get_string(s, "name", name, &name); + + // read realm + realm.reset(new RGWRealm(id, name)); + http_ret = realm->init(g_ceph_context, store); + if (http_ret < 0) + lderr(store->ctx()) << "failed to read realm id=" << id + << " name=" << name << dendl; +} + +void RGWOp_Realm_Get::send_response() +{ + set_req_state_err(s, http_ret); + dump_errno(s); + end_header(s); + + if (http_ret < 0) + return; + + encode_json("realm", *realm, s->formatter); + flusher.flush(); +} + +class RGWHandler_Realm : public RGWHandler_Auth_S3 { +protected: + RGWOp *op_get() { return new RGWOp_Realm_Get; } +}; + +RGWRESTMgr_Realm::RGWRESTMgr_Realm() +{ + // add the /admin/realm/period resource + register_resource("period", new RGWRESTMgr_Period); +} + - RGWHandler* RGWRESTMgr_Realm::get_handler(struct req_state*) ++RGWHandler_REST* RGWRESTMgr_Realm::get_handler(struct req_state*) +{ + return new RGWHandler_Realm; +} diff --cc src/rgw/rgw_rest_realm.h index d53e0607e7e,00000000000..cb61594595d mode 100644,000000..100644 --- a/src/rgw/rgw_rest_realm.h +++ b/src/rgw/rgw_rest_realm.h @@@ -1,16 -1,0 +1,16 @@@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_RGW_REST_REALM_H +#define CEPH_RGW_REST_REALM_H + +#include "rgw_rest.h" + +class RGWRESTMgr_Realm : public RGWRESTMgr { +public: + RGWRESTMgr_Realm(); + - RGWHandler* get_handler(struct req_state*) override; ++ RGWHandler_REST* get_handler(struct req_state*) override; +}; + +#endif diff --cc src/rgw/rgw_rest_s3.cc index fb4fe0835cc,9cbbd860aac..68b26c9fa6d --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@@ -105,29 -105,8 +105,30 @@@ int RGWGetObj_ObjStore_S3::send_respons return send_response_data(bl, 0 , 0); } +template +int decode_attr_bl_single_value(map& attrs, const char *attr_name, T *result, T def_val) +{ + map::iterator iter = attrs.find(attr_name); + if (iter == attrs.end()) { + *result = def_val; + return 0; + } + bufferlist& bl = iter->second; + if (bl.length() == 0) { + *result = def_val; + return 0; + } + bufferlist::iterator bliter = bl.begin(); + try { + ::decode(*result, bliter); + } catch (buffer::error& err) { + return -EIO; + } + return 0; +} + - int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) + int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, + off_t bl_len) { const char *content_type = NULL; string content_type_str; @@@ -163,21 -143,6 +165,21 @@@ if (s->system_request && lastmod) { /* we end up dumping mtime in two different methods, a bit redundant */ dump_epoch_header(s, "Rgwx-Mtime", lastmod); + uint64_t pg_ver; + int r = decode_attr_bl_single_value(attrs, RGW_ATTR_PG_VER, &pg_ver, (uint64_t)0); + if (r < 0) { + ldout(s->cct, 0) << "ERROR: failed to decode pg ver attr, ignoring" << dendl; + } - s->cio->print("Rgwx-Obj-PG-Ver: %lld\r\n", (long long)pg_ver); ++ STREAM_IO(s)->print("Rgwx-Obj-PG-Ver: %lld\r\n", (long long)pg_ver); + + uint32_t source_zone_short_id; + r = decode_attr_bl_single_value(attrs, RGW_ATTR_SOURCE_ZONE, &source_zone_short_id, (uint32_t)0); + if (r < 0) { + ldout(s->cct, 0) << "ERROR: failed to decode pg ver attr, ignoring" << dendl; + } + if (source_zone_short_id != 0) { - s->cio->print("Rgwx-Source-Zone-Short-Id: %lld\r\n", (long long)source_zone_short_id); ++ STREAM_IO(s)->print("Rgwx-Source-Zone-Short-Id: %lld\r\n", (long long)source_zone_short_id); + } } dump_content_length(s, total_len); @@@ -361,27 -310,22 +365,28 @@@ void RGWListBucket_ObjStore_S3::send_ve vector::iterator iter; for (iter = objs.begin(); iter != objs.end(); ++iter) { time_t mtime = iter->mtime.sec(); - const char *section_name = (iter->is_delete_marker() ? "DeleteMarker" : "Version"); - s->formatter->open_object_section(section_name); + const char *section_name = (iter->is_delete_marker() ? "DeleteMarker" + : "Version"); + s->formatter->open_array_section(section_name); + if (objs_container) { + s->formatter->dump_bool("IsDeleteMarker", iter->is_delete_marker()); + } if (encode_key) { - string key_name; - url_encode(iter->key.name, key_name); - s->formatter->dump_string("Key", key_name); + string key_name; + url_encode(iter->key.name, key_name); + s->formatter->dump_string("Key", key_name); } else { - s->formatter->dump_string("Key", iter->key.name); + s->formatter->dump_string("Key", iter->key.name); } string version_id = iter->key.instance; if (version_id.empty()) { - version_id = "null"; + version_id = "null"; } - if (s->system_request && iter->versioned_epoch > 0) { - s->formatter->dump_int("VersionedEpoch", iter->versioned_epoch); + if (s->system_request) { + if (iter->versioned_epoch > 0) { + s->formatter->dump_int("VersionedEpoch", iter->versioned_epoch); + } + s->formatter->dump_string("RgwxTag", iter->tag); } s->formatter->dump_string("VersionId", version_id); s->formatter->dump_bool("IsLatest", iter->is_current()); @@@ -394,16 -338,13 +399,17 @@@ dump_owner(s, iter->owner, iter->owner_display_name); s->formatter->close_section(); } + if (objs_container) { + s->formatter->close_section(); + } + if (!common_prefixes.empty()) { map::iterator pref_iter; - for (pref_iter = common_prefixes.begin(); pref_iter != common_prefixes.end(); ++pref_iter) { - s->formatter->open_array_section("CommonPrefixes"); - s->formatter->dump_string("Prefix", pref_iter->first); - s->formatter->close_section(); + for (pref_iter = common_prefixes.begin(); + pref_iter != common_prefixes.end(); ++pref_iter) { + s->formatter->open_array_section("CommonPrefixes"); + s->formatter->dump_string("Prefix", pref_iter->first); + s->formatter->close_section(); } } } @@@ -2913,13 -2858,16 +2950,16 @@@ int RGWHandler_Auth_S3::init(RGWRados * if (ret < 0) return ret; - return RGWHandler_ObjStore::init(store, state, cio); + return RGWHandler_REST::init(store, state, cio); } - RGWHandler *RGWRESTMgr_S3::get_handler(struct req_state *s) + RGWHandler_REST* RGWRESTMgr_S3::get_handler(struct req_state *s) { bool is_s3website = enable_s3website && (s->prot_flags & RGW_REST_WEBSITE); - int ret = RGWHandler_ObjStore_S3::init_from_header(s, is_s3website ? RGW_FORMAT_HTML : RGW_FORMAT_XML, true); + int ret = + RGWHandler_REST_S3::init_from_header(s, + is_s3website ? RGW_FORMAT_HTML : - RGW_FORMAT_XML, false); ++ RGW_FORMAT_XML, true); if (ret < 0) return NULL; diff --cc src/rgw/rgw_rest_s3.h index b718a278275,129934a9fdb..a97b82fe1cd --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@@ -415,12 -413,12 +416,11 @@@ class RGWHandler_REST_S3 : public RGWHa public: static int init_from_header(struct req_state *s, int default_formatter, bool configurable_format); - RGWHandler_ObjStore_S3() : RGWHandler_ObjStore() {} - virtual ~RGWHandler_ObjStore_S3() {} + RGWHandler_REST_S3() : RGWHandler_REST() {} + virtual ~RGWHandler_REST_S3() {} + - int validate_bucket_name(const string& bucket, bool relaxed_names) = delete; + int get_errordoc(const string& errordoc_key, string* error_content); - int validate_bucket_name(const string& bucket, bool relaxed_names); - using RGWHandler_ObjStore::validate_bucket_name; - virtual int init(RGWRados *store, struct req_state *s, RGWClientIO *cio); virtual int authorize() { return RGW_Auth_S3::authorize(store, s); diff --cc src/rgw/rgw_rest_swift.cc index 45e915f1dd9,0df6200fc10..d12f8650142 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@@ -456,10 -469,10 +469,10 @@@ int RGWCreateBucket_ObjStore_SWIFT::get } if (!has_policy) { - policy.create_default(s->user.user_id, s->user.display_name); + policy.create_default(s->user->user_id, s->user->display_name); } - location_constraint = store->region.api_name; + location_constraint = store->get_zonegroup().api_name; placement_rule = s->info.env->get("HTTP_X_STORAGE_POLICY", ""); return 0; diff --cc src/test/Makefile-client.am index d1b8d8d369a,c205cb81486..0c2efbd6473 --- a/src/test/Makefile-client.am +++ b/src/test/Makefile-client.am @@@ -662,24 -642,23 +651,24 @@@ bin_DEBUGPROGRAMS += ceph_test_rgw_ob ceph_test_cls_rgw_meta_SOURCES = test/test_rgw_admin_meta.cc ceph_test_cls_rgw_meta_LDADD = \ - $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ + $(LIBRGW) $(LIBRADOS) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -lexpat \ + libcls_timeindex_client.a \ - libcls_version_client.a libcls_log_client.a\ - libcls_statelog_client.a libcls_refcount_client.la \ - libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la + libcls_version_client.la libcls_log_client.la \ + libcls_statelog_client.la libcls_refcount_client.la \ + libcls_rgw_client.la libcls_user_client.la libcls_lock_client.la ceph_test_cls_rgw_meta_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw_meta ceph_test_cls_rgw_log_SOURCES = test/test_rgw_admin_log.cc ceph_test_cls_rgw_log_LDADD = \ - $(LIBRADOS) $(LIBRGW) $(CEPH_GLOBAL) \ + $(LIBRADOS) $(LIBRGW) $(LIBRGW_DEPS) $(CEPH_GLOBAL) \ $(UNITTEST_LDADD) $(CRYPTO_LIBS) \ -lcurl -lexpat \ - libcls_version_client.a libcls_log_client.a \ - libcls_statelog_client.a libcls_refcount_client.la \ - libcls_rgw_client.la libcls_user_client.a libcls_lock_client.la + libcls_version_client.la libcls_log_client.la \ + libcls_statelog_client.la libcls_refcount_client.la \ + libcls_rgw_client.la libcls_user_client.la libcls_lock_client.la ceph_test_cls_rgw_log_CXXFLAGS = $(UNITTEST_CXXFLAGS) bin_DEBUGPROGRAMS += ceph_test_cls_rgw_log