mirror of
https://github.com/ceph/ceph
synced 2026-08-02 07:03:18 +00:00
Run postauth hooks through the bytecode-capable Lua read path and keep the Lua request metadata adapters aligned with transparent HTTP argument lookup. The regression test verifies removed scripts stop affecting requests; the benchmark path showed a 500-statement hook dropping from 1961-1998ms to 372-393ms over 20K load/execute iterations, roughly an 80-81% reduction. Assisted-by: Codex:GPT-5 Signed-off-by: Jesse F. Williamson <jfw@ibm.com>
589 lines
18 KiB
C++
589 lines
18 KiB
C++
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
|
|
// vim: ts=8 sw=2 sts=2 expandtab ft=cpp
|
|
|
|
#include "common/errno.h"
|
|
#include "common/Throttle.h"
|
|
#include "common/WorkQueue.h"
|
|
#include "include/scope_guard.h"
|
|
|
|
#include <utility>
|
|
#include "rgw_auth_registry.h"
|
|
#include "rgw_dmclock_scheduler.h"
|
|
#include "rgw_rest.h"
|
|
#include "rgw_frontend.h"
|
|
#include "rgw_request.h"
|
|
#include "rgw_process.h"
|
|
#include "rgw_loadgen.h"
|
|
#include "rgw_client_io.h"
|
|
#include "rgw_opa.h"
|
|
#include "rgw_perf_counters.h"
|
|
#include "rgw_lua.h"
|
|
#include "rgw_lua_request.h"
|
|
#include "rgw_tracer.h"
|
|
#include "rgw_ratelimit.h"
|
|
#include "rgw_bucket_logging.h"
|
|
|
|
#include "services/svc_zone_utils.h"
|
|
|
|
#define dout_subsys ceph_subsys_rgw
|
|
|
|
using namespace std;
|
|
using rgw::dmclock::Scheduler;
|
|
|
|
void RGWProcess::RGWWQ::_dump_queue()
|
|
{
|
|
if (!g_conf()->subsys.should_gather<ceph_subsys_rgw, 20>()) {
|
|
return;
|
|
}
|
|
deque<RGWRequest *>::iterator iter;
|
|
if (process->m_req_queue.empty()) {
|
|
dout(20) << "RGWWQ: empty" << dendl;
|
|
return;
|
|
}
|
|
dout(20) << "RGWWQ:" << dendl;
|
|
for (iter = process->m_req_queue.begin();
|
|
iter != process->m_req_queue.end(); ++iter) {
|
|
dout(20) << "req: " << hex << *iter << dec << dendl;
|
|
}
|
|
} /* RGWProcess::RGWWQ::_dump_queue */
|
|
|
|
auto schedule_request(Scheduler *scheduler, req_state *s, RGWOp *op)
|
|
{
|
|
using rgw::dmclock::SchedulerCompleter;
|
|
if (!scheduler)
|
|
return std::make_pair(0,SchedulerCompleter{});
|
|
|
|
const auto client = op->dmclock_client();
|
|
const auto cost = op->dmclock_cost();
|
|
if (s->cct->_conf->subsys.should_gather(ceph_subsys_rgw, 10)) {
|
|
ldpp_dout(op,10) << "scheduling with "
|
|
<< s->cct->_conf.get_val<std::string>("rgw_scheduler_type")
|
|
<< " client=" << static_cast<int>(client)
|
|
<< " cost=" << cost << dendl;
|
|
}
|
|
return scheduler->schedule_request(client, {},
|
|
req_state::Clock::to_double(s->time),
|
|
cost,
|
|
s->yield);
|
|
}
|
|
|
|
bool RGWProcess::RGWWQ::_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;
|
|
}
|
|
|
|
RGWRequest* RGWProcess::RGWWQ::_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;
|
|
}
|
|
|
|
void RGWProcess::RGWWQ::_process(RGWRequest *req, ThreadPool::TPHandle &) {
|
|
perfcounter->inc(l_rgw_qactive);
|
|
process->handle_request(this, req);
|
|
process->req_throttle.put(1);
|
|
perfcounter->inc(l_rgw_qactive, -1);
|
|
}
|
|
bool rate_limit(rgw::sal::Driver* driver, req_state* s) {
|
|
// we dont want to limit health check or system or admin requests
|
|
if ((s->op_type == RGW_OP_GET_HEALTH_CHECK) || s->system_request)
|
|
return false;
|
|
std::string userfind;
|
|
RGWRateLimitInfo global_user;
|
|
RGWRateLimitInfo global_bucket;
|
|
RGWRateLimitInfo global_anon;
|
|
RGWRateLimitInfo* bucket_ratelimit;
|
|
RGWRateLimitInfo* user_ratelimit;
|
|
driver->get_ratelimit(global_bucket, global_user, global_anon);
|
|
bucket_ratelimit = &global_bucket;
|
|
user_ratelimit = &global_user;
|
|
s->user->get_id().to_str(userfind);
|
|
userfind = "u" + userfind;
|
|
s->ratelimit_user_name = userfind;
|
|
std::string bucketfind = !rgw::sal::Bucket::empty(s->bucket.get()) ? "b" + s->bucket->get_marker() : "";
|
|
s->ratelimit_bucket_marker = bucketfind;
|
|
const char *method = s->info.method;
|
|
|
|
bool is_sts_user = (s->auth.identity && s->auth.identity->get_identity_type() == TYPE_ROLE);
|
|
if (is_sts_user) {
|
|
ldpp_dout(s, 21) << "STS user detected: uid=" << std::quoted(s->user->get_id().to_str()) << dendl;
|
|
auto op_ret = s->user->read_attrs(s, s->yield);
|
|
if (op_ret < 0) {
|
|
ldpp_dout(s, 0) << "checking rate_limit: uid=" << std::quoted(s->user->get_id().to_str()) << " failed to read user attrs" << dendl;
|
|
}
|
|
}
|
|
auto iter = s->user->get_attrs().find(RGW_ATTR_RATELIMIT);
|
|
if(iter != s->user->get_attrs().end()) {
|
|
try {
|
|
RGWRateLimitInfo user_ratelimit_temp;
|
|
bufferlist& bl = iter->second;
|
|
auto biter = bl.cbegin();
|
|
decode(user_ratelimit_temp, biter);
|
|
// override global rate limiting only if local rate limiting is enabled
|
|
if (user_ratelimit_temp.enabled)
|
|
*user_ratelimit = user_ratelimit_temp;
|
|
} catch (buffer::error& err) {
|
|
ldpp_dout(s, 0) << "ERROR: failed to decode rate limit" << dendl;
|
|
return -EIO;
|
|
}
|
|
} else {
|
|
ldpp_dout(s, 21) << "checking rate_limit: uid=" << std::quoted(s->user->get_id().to_str()) << " does not have a rate limit attribute" << dendl;
|
|
}
|
|
if (s->user->get_id().id == RGW_USER_ANON_ID && global_anon.enabled) {
|
|
*user_ratelimit = global_anon;
|
|
}
|
|
int64_t limit_bucket = 0;
|
|
int64_t limit_user = s->ratelimit_data->should_rate_limit(method, s->ratelimit_user_name, s->time, user_ratelimit, s->info.request_params);
|
|
|
|
if(!rgw::sal::Bucket::empty(s->bucket.get()))
|
|
{
|
|
iter = s->bucket->get_attrs().find(RGW_ATTR_RATELIMIT);
|
|
if(iter != s->bucket->get_attrs().end()) {
|
|
try {
|
|
RGWRateLimitInfo bucket_ratelimit_temp;
|
|
bufferlist& bl = iter->second;
|
|
auto biter = bl.cbegin();
|
|
decode(bucket_ratelimit_temp, biter);
|
|
// override global rate limiting only if local rate limiting is enabled
|
|
if (bucket_ratelimit_temp.enabled)
|
|
*bucket_ratelimit = bucket_ratelimit_temp;
|
|
} catch (buffer::error& err) {
|
|
ldpp_dout(s, 0) << "ERROR: failed to decode rate limit" << dendl;
|
|
return -EIO;
|
|
}
|
|
}
|
|
if (!limit_user) {
|
|
limit_bucket = s->ratelimit_data->should_rate_limit(method, s->ratelimit_bucket_marker, s->time, bucket_ratelimit, s->info.request_params);
|
|
}
|
|
}
|
|
if(limit_bucket && !limit_user) {
|
|
s->ratelimit_data->giveback_tokens(method, s->ratelimit_user_name, s->info.request_params, user_ratelimit);
|
|
}
|
|
s->user_ratelimit = *user_ratelimit;
|
|
s->bucket_ratelimit = *bucket_ratelimit;
|
|
int64_t delay = limit_user ? limit_user : limit_bucket;
|
|
if (delay > 0) {
|
|
s->ratelimit_retry_after = delay;
|
|
}
|
|
return (limit_user || limit_bucket);
|
|
}
|
|
|
|
static int execute_post_auth_lua_script(RGWOp * const op, req_state * const s)
|
|
{
|
|
if (op->get_type() == RGW_OP_GET_HEALTH_CHECK) {
|
|
return 0;
|
|
}
|
|
|
|
const auto [script, rc] = rgw::lua::read_script_or_bytecode(
|
|
s, s->penv.lua.manager.get(), s->bucket_tenant, s->yield,
|
|
rgw::lua::context::postAuth);
|
|
if (rc == -ENOENT) {
|
|
return 0;
|
|
}
|
|
|
|
if (rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to execute post authorization script. "
|
|
"error: " << rc << dendl;
|
|
return 0;
|
|
}
|
|
|
|
int script_return_code = 0;
|
|
const auto execute_rc = rgw::lua::request::execute(
|
|
s->penv.rest, s->penv.olog.get(), s, op, script, script_return_code);
|
|
if (execute_rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to execute post authorization script. "
|
|
"error: " << execute_rc << dendl;
|
|
}
|
|
|
|
if (script_return_code == -EPERM) {
|
|
return script_return_code;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rgw_process_authenticated(RGWHandler_REST * const handler,
|
|
RGWOp *& op,
|
|
RGWRequest * const req,
|
|
req_state * const s,
|
|
optional_yield y,
|
|
rgw::sal::Driver* driver,
|
|
const bool skip_retarget)
|
|
{
|
|
ldpp_dout(op, 2) << "init permissions" << dendl;
|
|
int ret = handler->init_permissions(op, y);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Only some accesses support website mode, and website mode does NOT apply
|
|
* if you are using the REST endpoint either (ergo, no authenticated access)
|
|
*/
|
|
if (! skip_retarget) {
|
|
ldpp_dout(op, 2) << "recalculating target" << dendl;
|
|
ret = handler->retarget(op, &op, y);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
req->op = op;
|
|
} else {
|
|
ldpp_dout(op, 2) << "retargeting skipped because of SubOp mode" << dendl;
|
|
}
|
|
|
|
/* If necessary extract object ACL and put them into req_state. */
|
|
ldpp_dout(op, 2) << "reading permissions" << dendl;
|
|
ret = handler->read_permissions(op, y);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "init op" << dendl;
|
|
ret = op->init_processing(y);
|
|
if (op->get_type() == RGW_OP_OPTIONS_CORS && ret == -EINVAL) {
|
|
ldpp_dout(op, 0) << "NOTICE: RGW_OP_OPTIONS_CORS shouldn't return -EINVAL in case we have a global CORS!" << dendl;
|
|
ret = 0;
|
|
}
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "verifying op mask" << dendl;
|
|
ret = op->verify_op_mask();
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* Check if OPA is used to authorize requests */
|
|
if (s->cct->_conf->rgw_use_opa_authz) {
|
|
ret = rgw_opa_authorize(op, s);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "verifying op permissions" << dendl;
|
|
{
|
|
auto span = tracing::rgw::tracer.add_span("verify_permission", s->trace);
|
|
std::swap(span, s->trace);
|
|
ret = op->verify_permission(y);
|
|
std::swap(span, s->trace);
|
|
}
|
|
if (ret == -EACCES || ret == -EPERM || ret == -ERR_AUTHORIZATION) {
|
|
// system requests may impersonate another user/role for permission checks
|
|
// so only rely on is_admin() to override permissions
|
|
if (s->auth.identity->is_admin()) {
|
|
dout(2) << "overriding permissions due to admin operation" << dendl;
|
|
} else {
|
|
return ret;
|
|
}
|
|
} else if (ret < 0) {
|
|
// other errors are not overridden as they might be invalid input
|
|
return ret;
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "verifying op params" << dendl;
|
|
ret = op->verify_params();
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "pre-executing" << dendl;
|
|
op->pre_exec();
|
|
|
|
ldpp_dout(op, 2) << "check rate limiting" << dendl;
|
|
if (rate_limit(driver, s)) {
|
|
return -ERR_RATE_LIMITED;
|
|
}
|
|
|
|
ret = execute_post_auth_lua_script(op, s);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "executing" << dendl;
|
|
{
|
|
auto span = tracing::rgw::tracer.add_span("execute", s->trace);
|
|
std::swap(span, s->trace);
|
|
op->execute(y);
|
|
std::swap(span, s->trace);
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "completing" << dendl;
|
|
op->complete();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int process_request(const RGWProcessEnv& penv,
|
|
RGWRequest* const req,
|
|
const std::string& frontend_prefix,
|
|
RGWRestfulIO* const client_io,
|
|
optional_yield yield,
|
|
rgw::dmclock::Scheduler *scheduler,
|
|
string* user,
|
|
ceph::coarse_real_clock::duration* latency,
|
|
int* http_ret)
|
|
{
|
|
int ret = client_io->init(g_ceph_context);
|
|
rgw::sal::Driver* driver = penv.driver;
|
|
auto trans_id = driver->zone_unique_trans_id(req->id);
|
|
dout(1) << "====== starting new request req=" << hex << req << dec
|
|
<< " request_id=" << trans_id << " =====" << dendl;
|
|
perfcounter->inc(l_rgw_req);
|
|
|
|
RGWEnv& rgw_env = client_io->get_env();
|
|
|
|
req_state rstate(g_ceph_context, penv, &rgw_env, req->id);
|
|
req_state *s = &rstate;
|
|
|
|
s->ratelimit_data = penv.ratelimiting->get_active();
|
|
|
|
std::unique_ptr<rgw::sal::User> u = driver->get_user(rgw_user());
|
|
s->set_user(u);
|
|
|
|
if (ret < 0) {
|
|
s->cio = client_io;
|
|
abort_early(s, nullptr, ret, nullptr, yield);
|
|
return ret;
|
|
}
|
|
|
|
s->req_id = driver->zone_unique_id(req->id);
|
|
s->trans_id = trans_id;
|
|
s->host_id = driver->get_host_id();
|
|
s->yield = yield;
|
|
|
|
RGWOp* op = nullptr;
|
|
int init_error = 0;
|
|
bool should_log = false;
|
|
RGWREST* rest = penv.rest;
|
|
RGWRESTMgr *mgr;
|
|
bool is_health_request = false;
|
|
RGWHandler_REST *handler = rest->get_handler(driver, s,
|
|
*penv.auth_registry,
|
|
frontend_prefix,
|
|
client_io, &mgr, &init_error);
|
|
|
|
// RAII handlers to keep these around during process_request():
|
|
auto put_handler_guard = make_scope_guard([rest, &handler] {
|
|
rest->put_handler(handler);
|
|
});
|
|
|
|
auto put_op_guard = make_scope_guard([&handler, &op] {
|
|
if (handler) {
|
|
handler->put_op(op);
|
|
}
|
|
});
|
|
|
|
rgw::dmclock::SchedulerCompleter c;
|
|
|
|
if (init_error != 0) {
|
|
abort_early(s, nullptr, init_error, nullptr, yield);
|
|
goto done;
|
|
}
|
|
ldpp_dout(s, 10) << "handler=" << typeid(*handler).name() << dendl;
|
|
|
|
should_log = mgr->get_logging();
|
|
|
|
ldpp_dout(s, 2) << "getting op " << s->op << dendl;
|
|
op = handler->get_op();
|
|
if (!op) {
|
|
abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED, handler, yield);
|
|
goto done;
|
|
}
|
|
std::tie(ret,c) = schedule_request(scheduler, s, op);
|
|
if (ret < 0) {
|
|
if (ret == -EAGAIN) {
|
|
ret = -ERR_RATE_LIMITED;
|
|
}
|
|
ldpp_dout(op,0) << "Scheduling request failed with " << ret << dendl;
|
|
abort_early(s, op, ret, handler, yield);
|
|
goto done;
|
|
}
|
|
req->op = op;
|
|
ldpp_dout(op, 10) << "op=" << typeid(*op).name() << " " << dendl;
|
|
s->op_type = op->get_type();
|
|
try {
|
|
ldpp_dout(op, 2) << "verifying requester" << dendl;
|
|
ret = op->verify_requester(*penv.auth_registry, yield);
|
|
if (ret < 0) {
|
|
dout(10) << "failed to authorize request" << dendl;
|
|
abort_early(s, op, ret, handler, yield);
|
|
goto done;
|
|
}
|
|
|
|
/* FIXME: remove this after switching all handlers to the new authentication
|
|
* infrastructure. */
|
|
if (nullptr == s->auth.identity) {
|
|
auto result = rgw::auth::transform_old_authinfo(
|
|
op, yield, driver, s->user.get());
|
|
if (!result) {
|
|
abort_early(s, op, result.error(), handler, yield);
|
|
goto done;
|
|
}
|
|
s->auth.identity = std::move(result).value();
|
|
}
|
|
|
|
ldpp_dout(op, 2) << "normalizing buckets and tenants" << dendl;
|
|
ret = handler->postauth_init(yield);
|
|
if (ret < 0) {
|
|
dout(10) << "failed to run post-auth init" << dendl;
|
|
abort_early(s, op, ret, handler, yield);
|
|
goto done;
|
|
}
|
|
|
|
if (s->user->get_info().suspended) {
|
|
dout(10) << "user is suspended, uid=" << s->user->get_id() << dendl;
|
|
abort_early(s, op, -ERR_USER_SUSPENDED, handler, yield);
|
|
goto done;
|
|
}
|
|
|
|
is_health_request = (op->get_type() == RGW_OP_GET_HEALTH_CHECK);
|
|
{
|
|
s->trace_enabled = tracing::rgw::tracer.is_enabled();
|
|
if (!is_health_request) {
|
|
auto [lua_script, rc] = rgw::lua::read_script_or_bytecode(s, penv.lua.manager.get(),
|
|
s->bucket_tenant, s->yield,
|
|
rgw::lua::context::preRequest);
|
|
if (rc == -ENOENT) {
|
|
// no script, nothing to do
|
|
} else if (rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to execute pre request script. "
|
|
"error: " << rc << dendl;
|
|
} else {
|
|
int script_return_code = 0;
|
|
rc = rgw::lua::request::execute(rest, penv.olog.get(), s, op, lua_script, script_return_code);
|
|
|
|
if (rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to execute pre request script. "
|
|
"error: " << rc << dendl;
|
|
}
|
|
if (script_return_code == -EPERM) {
|
|
abort_early(s, op, script_return_code, handler, yield);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
s->trace = tracing::rgw::tracer.start_trace(op->name(), s->trace_enabled);
|
|
s->trace->SetAttribute(tracing::rgw::TRANS_ID, s->trans_id);
|
|
|
|
ret = rgw_process_authenticated(handler, op, req, s, yield, driver);
|
|
if (ret < 0) {
|
|
abort_early(s, op, ret, handler, yield);
|
|
goto done;
|
|
}
|
|
} catch (const ceph::crypto::DigestException& e) {
|
|
dout(0) << "authentication failed" << e.what() << dendl;
|
|
abort_early(s, op, -ERR_INVALID_SECRET_KEY, handler, yield);
|
|
}
|
|
|
|
done:
|
|
if (op) {
|
|
if (s->trace) {
|
|
s->trace->SetAttribute(tracing::rgw::OP_RESULT, op->get_ret());
|
|
s->trace->SetAttribute(tracing::rgw::HOST_ID, driver->get_host_id());
|
|
|
|
if (!rgw::sal::User::empty(s->user)) {
|
|
s->trace->SetAttribute(tracing::rgw::USER_ID, s->user->get_id().id);
|
|
}
|
|
if (!rgw::sal::Bucket::empty(s->bucket)) {
|
|
s->trace->SetAttribute(tracing::rgw::BUCKET_NAME, s->bucket->get_name());
|
|
}
|
|
if (!rgw::sal::Object::empty(s->object)) {
|
|
s->trace->SetAttribute(tracing::rgw::OBJECT_NAME, s->object->get_name());
|
|
}
|
|
}
|
|
if (!is_health_request) {
|
|
auto [lua_script, rc] = rgw::lua::read_script_or_bytecode(s, penv.lua.manager.get(),
|
|
s->bucket_tenant, s->yield,
|
|
rgw::lua::context::postRequest);
|
|
if (rc == -ENOENT) {
|
|
// no script, nothing to do
|
|
} else if (rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to read post request script. "
|
|
"error: " << rc << dendl;
|
|
} else {
|
|
rc = rgw::lua::request::execute(rest, penv.olog.get(), s, op, lua_script);
|
|
if (rc < 0) {
|
|
ldpp_dout(op, 5) <<
|
|
"WARNING: failed to execute post request script. "
|
|
"error: " << rc << dendl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
client_io->complete_request();
|
|
} catch (rgw::io::Exception& e) {
|
|
dout(0) << "ERROR: client_io->complete_request() returned "
|
|
<< e.what() << dendl;
|
|
perfcounter->inc(l_rgw_qlen, -1);
|
|
perfcounter->inc(l_rgw_qactive, -1);
|
|
}
|
|
if (should_log) {
|
|
rgw_log_op(rest, s, op, penv.olog.get());
|
|
}
|
|
|
|
if (op && op->always_do_bucket_logging()) {
|
|
std::ignore = rgw::bucketlogging::log_record(driver,
|
|
rgw::bucketlogging::LoggingType::Standard,
|
|
s->object.get(),
|
|
s,
|
|
op->canonical_name(),
|
|
"",
|
|
(s->src_object ? s->src_object->get_size() : (s->object ? s->object->get_size() : 0)),
|
|
op,
|
|
yield,
|
|
true,
|
|
false);
|
|
}
|
|
|
|
if (http_ret != nullptr) {
|
|
*http_ret = s->err.http_ret;
|
|
}
|
|
int op_ret = 0;
|
|
|
|
if (user && !rgw::sal::User::empty(s->user.get())) {
|
|
*user = s->user->get_id().to_str();
|
|
}
|
|
|
|
if (op) {
|
|
op_ret = op->get_ret();
|
|
ldpp_dout(op, 2) << "op status=" << op_ret << dendl;
|
|
ldpp_dout(op, 2) << "http status=" << s->err.http_ret << dendl;
|
|
} else {
|
|
ldpp_dout(s, 2) << "http status=" << s->err.http_ret << dendl;
|
|
}
|
|
|
|
const auto lat = s->time_elapsed();
|
|
if (latency) {
|
|
*latency = lat;
|
|
}
|
|
dout(1) << "====== req done req=" << hex << req << dec
|
|
<< " op=" << (op ? op->name() : "unknown")
|
|
<< " bucket=" << s->bucket_name
|
|
<< " status=" << op_ret
|
|
<< " http_status=" << s->err.http_ret
|
|
<< " latency=" << lat
|
|
<< " request_id=" << s->trans_id
|
|
<< " ======"
|
|
<< dendl;
|
|
|
|
return (ret < 0 ? ret : s->err.ret);
|
|
} /* process_request */
|