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)
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)
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) \
#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<RGWLibRequest*>(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<RGWOp*>(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<RGWOp*>(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<RGWOp*>(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<const char*> args;
+ return init(args);
}
- catch (...) {
- lderr(rgw) << "librgw_acl_bin2xml: caught unknown exception " << dendl;
+
+ int RGWLib::init(vector<const char*>& args)
+ {
+ int r = 0;
+
+ /* alternative default for module */
+ vector<const char *> 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<std::mutex> lg(librgw_mtx);
+ if (! g_ceph_context) {
+ vector<const char*> args;
+ argv_to_vec(argc, const_cast<const char**>(argv), args);
+ rc = rgwlib.init(args);
+ }
+ }
+
+ *rgw = g_ceph_context->get();
+
+ return rc;
}
void librgw_shutdown(librgw_t rgw)
void _usage()
{
- cerr << "usage: radosgw-admin <cmd> [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=<id> user id\n";
- cerr << " --subuser=<name> subuser name\n";
- cerr << " --access-key=<key> S3 access key\n";
- cerr << " --email=<email>\n";
- cerr << " --secret/--secret-key=<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=<type> key type, options are: swift, s3\n";
- cerr << " --temp-url-key[-2]=<key> temp url key\n";
- cerr << " --access=<access> Set access permissions for sub-user, should be one\n";
- cerr << " of read, write, readwrite, full\n";
- cerr << " --display-name=<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=<bucket>\n";
- cerr << " --pool=<pool>\n";
- cerr << " --object=<object>\n";
- cerr << " --date=<date>\n";
- cerr << " --start-date=<date>\n";
- cerr << " --end-date=<date>\n";
- cerr << " --bucket-id=<bucket-id>\n";
- cerr << " --shard-id=<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> key to retrieve metadata from with metadata get\n";
- cerr << " --remote=<remote> remote to pull period\n";
- cerr << " --parent=<id> parent period id\n";
- cerr << " --period=<id> period id\n";
- cerr << " --epoch=<number> 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=<id> master zonegroup id\n";
- cerr << " --master-zone=<id> master zone id\n";
- cerr << " --rgw-realm=<realm> realm name\n";
- cerr << " --realm-id=<realm id> realm id\n";
- cerr << " --realm-new-name=<realm new name> realm new name\n";
- cerr << " --rgw-zonegroup=<zonegroup> zonegroup name\n";
- cerr << " --rgw-zone=<zone> zone in which radosgw is running\n";
- cerr << " --zone-new-name=<zone> zone new name\n";
- cerr << " --default set entity (realm, zonegroup, zone) as default\n";
- cerr << " --endpoints=<list> 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=<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=<flag> enable/disable dump of log entries on log show\n";
- cerr << " --show-log-sum=<flag> 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=<state string> 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=<list> comma separated list of categories, used in usage show\n";
- cerr << " --caps=<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 << "<date> := \"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 <cmd> [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> tenant name\n";
+ cout << " --uid=<id> user id\n";
+ cout << " --subuser=<name> subuser name\n";
+ cout << " --access-key=<key> S3 access key\n";
+ cout << " --email=<email>\n";
+ cout << " --secret/--secret-key=<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=<type> key type, options are: swift, s3\n";
+ cout << " --temp-url-key[-2]=<key> temp url key\n";
+ cout << " --access=<access> Set access permissions for sub-user, should be one\n";
+ cout << " of read, write, readwrite, full\n";
+ cout << " --display-name=<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=<bucket>\n";
+ cout << " --pool=<pool>\n";
+ cout << " --object=<object>\n";
+ cout << " --date=<date>\n";
+ cout << " --start-date=<date>\n";
+ cout << " --end-date=<date>\n";
+ cout << " --bucket-id=<bucket-id>\n";
+ cout << " --shard-id=<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> key to retrieve metadata from with metadata get\n";
- cout << " --rgw-region=<region> region in which radosgw is running\n";
++ cout << " --remote=<remote> remote to pull period\n";
++ cout << " --parent=<id> parent period id\n";
++ cout << " --period=<id> period id\n";
++ cout << " --epoch=<number> 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=<id> master zonegroup id\n";
++ cout << " --master-zone=<id> master zone id\n";
++ cout << " --rgw-realm=<realm> realm name\n";
++ cout << " --realm-id=<realm id> realm id\n";
++ cout << " --realm-new-name=<realm new name> realm new name\n";
++ cout << " --rgw-zonegroup=<zonegroup> zonegroup name\n";
+ cout << " --rgw-zone=<zone> zone in which radosgw is running\n";
++ cout << " --zone-new-name=<zone> zone new name\n";
++ cout << " --default set entity (realm, zonegroup, zone) as default\n";
++ cout << " --endpoints=<list> 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=<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=<flag> enable/disable dump of log entries on log show\n";
+ cout << " --show-log-sum=<flag> 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=<file> specify a file to read in when setting data\n";
+ cout << " --state=<state string> 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=<list> comma separated list of categories, used in usage show\n";
+ cout << " --caps=<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 << "<date> := \"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();
}
--- /dev/null
- RGWProcessEnv* pe = static_cast<RGWProcessEnv *>(req_info->user_data);
+ // -*- 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);
- RGWRequest* req = new RGWRequest(store->get_new_req_id());
++ RGWMongooseEnv* pe = static_cast<RGWMongooseEnv *>(req_info->user_data);
+ RGWRados* store = pe->store;
+ RGWREST* rest = pe->rest;
+ OpsLogSocket* olog = pe->olog;
+
- 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;
- }
++ RGWRequest req(store->get_new_req_id());
+ RGWMongoose client_io(conn, pe->port);
+
- delete req;
++ {
++ // hold a read lock over access to pe->store for reconfiguration
++ RWLock::RLocker lock(pe->mutex);
+
++ 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<string, string> 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<string, string>::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] : "<null>") << 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 */
}
/** 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);
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<string, string> 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<string, bufferlist> 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<string, string> 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<string, bufferlist> 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 */
--- /dev/null
- RGWProcessEnv env;
+ // -*- 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<string, string> config_map;
+ int parse_config(const string& config, map<string, string>& 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<string, string>& 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;
++ RGWMongooseEnv env;
+
+ void set_conf_default(map<string, string>& 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<string, RGWAccessKey>::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<RGWFrontend*> &frontends;
++ RGWRealmReloader::Pauser* pauser;
++ public:
++ RGWFrontendPauser(std::list<RGWFrontend*> &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 */
--- /dev/null
+ // -*- 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 <mutex>
+ #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<const char *>& 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 */
#include <curl/curl.h>
+#include <boost/intrusive_ptr.hpp>
+
#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"
#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"
return mgr;
}
-
- int RGWFrontendConfig::parse_config(const string& config, map<string, string>& config_map)
- {
- list<string> config_list;
- get_str_list(config, " ", config_list);
-
- list<string>::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<string, string>::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<string, RGWAccessKey>::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<string, string>& 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<string, string> 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<string, string>::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] : "<null>") << 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<RGWFrontend*> &frontends;
- RGWRealmReloader::Pauser* pauser;
- public:
- RGWFrontendPauser(std::list<RGWFrontend*> &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
*/
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;
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;
}
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)
}
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. */
}
/* 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;
}
--- /dev/null
+ // -*- 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<RGWRequest*> 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<RGWRequest> {
+ RGWProcess* process;
+ RGWWQ(RGWProcess* p, time_t timeout, time_t suicide_timeout, ThreadPool* tp)
+ : ThreadPool::WorkQueue<RGWRequest>("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<RGWRequest>::_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 */
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;
* 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;
--- /dev/null
- RGWHandler* get_handler(struct req_state*) override {
+// -*- 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* RGWRESTMgr_Realm::get_handler(struct req_state*)
++ RGWHandler_REST* get_handler(struct req_state*) override {
+ return new RGWHandler_Period;
+ }
+};
+
+
+// GET /admin/realm
+class RGWOp_Realm_Get : public RGWRESTOp {
+ std::unique_ptr<RGWRealm> 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_REST* RGWRESTMgr_Realm::get_handler(struct req_state*)
+{
+ return new RGWHandler_Realm;
+}
--- /dev/null
- RGWHandler* get_handler(struct req_state*) override;
+// -*- 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_REST* get_handler(struct req_state*) override;
+};
+
+#endif
return send_response_data(bl, 0 , 0);
}
- int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, off_t bl_len)
+template <class T>
+int decode_attr_bl_single_value(map<string, bufferlist>& attrs, const char *attr_name, T *result, T def_val)
+{
+ map<string, bufferlist>::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)
{
const char *content_type = NULL;
string content_type_str;
if (s->system_request && lastmod) {
/* we end up dumping mtime in two different methods, a bit redundant */
dump_epoch_header(s, "Rgwx-Mtime", lastmod);
- s->cio->print("Rgwx-Obj-PG-Ver: %lld\r\n", (long long)pg_ver);
+ 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-Source-Zone-Short-Id: %lld\r\n", (long long)source_zone_short_id);
++ 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) {
++ STREAM_IO(s)->print("Rgwx-Source-Zone-Short-Id: %lld\r\n", (long long)source_zone_short_id);
+ }
}
dump_content_length(s, total_len);
vector<RGWObjEnt>::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());
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<string, bool>::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();
}
}
}
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;
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);
}
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;
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_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_timeindex_client.a \
+ 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