Merge PR #66769 into tentacle

* refs/pull/66769/head:
	test/rgw/logging: run teuthology on erasure coded pool
	rgw/bucket-logging: support for EC pools
	rgw/logging: do not create empty temporary objects
	rgw/logging: deleteting the object holding the temp object name on cleanup
	rgw/logging: make sure source bucket is in the target's list
	rgw/logging: removed unused APIs from header
	rgw/logging: fix race condition when name update returns ECANCELED
	rgw/logging: add error message when log_record fails
	rgw/logging: rollover objects when conf changes
	rgw/logging: allow committing empty objects
	rgw/logging: verify http method exists
	rgw/logging: fix/remove/add bucket logging op names
	rgw/logging: refactor canonical_name()
	rgw/logging: fix canonical names
	rgw: RGWPostBucketLoggingOp uses yield context

Reviewed-by: Anthony D Atri <anthony.datri@gmail.com>
Reviewed-by: Yuval Lifshitz <ylifshit@redhat.com>
This commit is contained in:
Patrick Donnelly 2026-05-08 22:33:32 -04:00
commit fa5ecb2232
No known key found for this signature in database
GPG Key ID: 053758C0A8A3CE2F
37 changed files with 1647 additions and 325 deletions

View File

@ -4,6 +4,8 @@
>=20.0.0
* RGW: Bucket Logging suppports creating log buckets in EC pools.
Implicit logging object commits are now performed asynchronously.
* RADOS: leader monitor and stretch mode status are now included in the `ceph status` output.
Related Tracker: https://tracker.ceph.com/issues/70406
* RGW: The User Account feature introduced in Squid provides first-class support for

View File

@ -306,6 +306,8 @@ values to their defaults or to a level suitable for normal operations.
+--------------------------+-----------+--------------+
| ``rgw notification`` | 1 | 5 |
+--------------------------+-----------+--------------+
| ``rgw bucket logging`` | 1 | 5 |
+--------------------------+-----------+--------------+
| ``javaclient`` | 1 | 5 |
+--------------------------+-----------+--------------+
| ``asok`` | 1 | 5 |

View File

@ -54,6 +54,22 @@ them, regardless if enough time passed or if no more records are written to the
object. Flushing will happen automatically when logging is disabled on a
bucket, or its logging configuration is changed, or the bucket is deleted.
The process of adding a new log object to the log bucket is asynchronous when
triggered by a log record being written. Consequently, the operation that
generated the log is completed immediately and does not wait for the log object
addition to finish; this addition occurs later.
The log object is added to the log bucket immediately when flushed. Consequently,
this action may result in temporary gaps in the log records within the bucket
until any pending log objects are also added.
To check which log objects for a source bucket are currently pending addition to
the log bucket, execute the following command:
.. prompt:: bash #
radosgw-admin bucket logging list --bucket <source bucket>
Standard
````````
If the logging type is set to "Standard" (the default) the log records are

View File

@ -645,7 +645,7 @@ Parameters
Response Entities
~~~~~~~~~~~~~~~~~
Response is XML encoded in the body of the request, in the following format:
The response is XML encoded in the body of the request, in the following format:
::
@ -786,7 +786,7 @@ Parameters are XML encoded in the body of the request, in the following format:
| | | between different source buckets writing log records to the same log bucket. | |
+-------------------------------+-----------+--------------------------------------------------------------------------------------+----------+
| ``LoggingType`` | String | The type of logging. Valid values are: | No |
| | | ``Standard`` (default) all bucket operations are logged after being perfomed. | |
| | | ``Standard`` (default) all bucket operations are logged after being performed. | |
| | | The log record will contain all fields. | |
| | | ``Journal`` only operations that modify and object are logged. | |
| | | Will record the minimum subset of fields in the log record that is needed | |
@ -796,6 +796,18 @@ Parameters are XML encoded in the body of the request, in the following format:
| | | object added to the log bucket. Default is 3600 seconds (1 hour). | |
+-------------------------------+-----------+--------------------------------------------------------------------------------------+----------+
Response Entities
~~~~~~~~~~~~~~~~~
The response is XML encoded in the body of the request, only if a configuration change triggers flushing of the current logging object.
In this case it will return the name of the flushed logging object in following format:
::
<PostBucketLoggingOutput xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<FlushedLoggingObject>string</FlushedLoggingObject>
</PostBucketLoggingOutput>
HTTP Response
~~~~~~~~~~~~~
@ -860,7 +872,7 @@ Syntax
Response Entities
~~~~~~~~~~~~~~~~~
Response header contains ``Last-Modified`` date/time of the logging configuration.
The response header contains ``Last-Modified`` date/time of the logging configuration.
Logging configuration is XML encoded in the body of the response, in the following format:
::
@ -915,7 +927,7 @@ Flush Bucket Logging
--------------------
Flushes logging object for a given source bucket (if not flushed, the logging objects are written lazily to the log bucket).
Returns the name of the object that was flushed. An empty name will be returned if no object needs to be flushed.
Returns the name of the object that was flushed. Flushing will happen even if the logging object is empty.
Syntax
~~~~~~
@ -927,7 +939,7 @@ Syntax
Response Entities
~~~~~~~~~~~~~~~~~
Response is XML encoded in the body of the request, in the following format:
The response is XML encoded in the body of the request, in the following format:
::

View File

@ -24,6 +24,17 @@
"output": {"shape": "PostBucketLoggingOutput"},
"documentationUrl":"https://docs.ceph.com/docs/master/radosgw/s3/bucketops/#post-bucket-logging",
"documentation":"<p>Flushes the logging objects of the buckets.</p>"
},
"PutBucketLogging":{
"name":"PutBucketLogging",
"http":{
"method":"PUT",
"requestUri":"/{Bucket}?logging"
},
"input":{"shape":"PutBucketLoggingRequest"},
"output": {"shape": "PutBucketLoggingOutput"},
"documentationUrl":"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLogging.html",
"documentation":"<p>Put bucket logging configuration on source bucket.</p>"
},
"GetUsageStats":{
"name":"GetUsageStats",
@ -402,6 +413,15 @@
}
}
},
"PutBucketLoggingOutput": {
"type":"structure",
"members":{
"FlushedLoggingObject": {
"shape":"FlushedLoggingObject",
"documentation":"<p>Name of the pending logging object that was flushed.</p>"
}
}
},
"FlushedLoggingObject":{
"type":"string"
},

View File

@ -0,0 +1 @@
../.qa/

View File

@ -0,0 +1,3 @@
overrides:
rgw:
ec-data-pool: true

View File

@ -0,0 +1,3 @@
overrides:
rgw:
ec-data-pool: false

View File

@ -68,6 +68,7 @@ SUBSYS(rgw_flight, 1, 5)
SUBSYS(rgw_lifecycle, 1, 5)
SUBSYS(rgw_restore, 1, 5)
SUBSYS(rgw_notification, 1, 5)
SUBSYS(rgw_bucket_logging, 1, 5)
SUBSYS(javaclient, 1, 5)
SUBSYS(asok, 1, 5)
SUBSYS(throttle, 1, 1)

View File

@ -174,6 +174,7 @@ set(librgw_common_srcs
driver/rados/groups.cc
driver/rados/rgw_bucket.cc
driver/rados/rgw_bucket_sync.cc
driver/rados/rgw_bl_rados.cc
driver/rados/rgw_cr_rados.cc
driver/rados/rgw_cr_tools.cc
driver/rados/rgw_d3n_datacache.cc

View File

@ -0,0 +1,832 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
#include "rgw_bucket_logging.h"
#include "rgw_bl_rados.h"
#include <chrono>
#include <fmt/format.h>
#include <future>
#include <memory>
#include <thread>
#include <boost/algorithm/hex.hpp>
#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/context/protected_fixedsize_stack.hpp>
#include "common/async/yield_context.h"
#include "common/async/yield_waiter.h"
#include "common/ceph_time.h"
#include "common/dout.h"
#include "cls/lock/cls_lock_client.h"
#include "include/common_fwd.h"
#include "include/function2.hpp"
#include "librados/AioCompletionImpl.h"
#include "services/svc_zone.h"
#include "rgw_common.h"
#include "rgw_perf_counters.h"
#include "rgw_sal_rados.h"
#include "rgw_zone_features.h"
#define dout_subsys ceph_subsys_rgw_bucket_logging
namespace rgw::bucketlogging {
using commit_list_t = std::set<std::string>;
// use mmap/mprotect to allocate 128k coroutine stacks
auto make_stack_allocator() {
return boost::context::protected_fixedsize_stack{128*1024};
}
const std::string COMMIT_LIST_OBJECT_NAME = "bucket_logging_global_commit_list";
static const std::string TEMP_POOL_ATTR = "temp_logging_pool";
static std::string get_commit_list_name (const rgw::sal::Bucket* log_bucket,
const std::string& prefix) {
return fmt::format("{}/{}/{}/{}", log_bucket->get_tenant(),
log_bucket->get_name(),
log_bucket->get_bucket_id(), prefix);
}
int add_commit_target_entry(const DoutPrefixProvider* dpp,
rgw::sal::RadosStore* store,
const rgw::sal::Bucket* log_bucket,
const std::string& prefix,
const std::string& obj_name,
const std::string& tail_obj_name,
const rgw_pool& temp_data_pool,
optional_yield y) {
auto& ioctx_logging = store->getRados()->get_logging_pool_ctx();
std::string target_obj_name = get_commit_list_name (log_bucket, prefix);
{
librados::ObjectWriteOperation op;
op.create(false);
bufferlist bl;
bl.append(tail_obj_name);
std::map<std::string, bufferlist> new_commit_list{{obj_name, bl}};
op.omap_set(new_commit_list);
bufferlist pool_bl;
encode(temp_data_pool, pool_bl);
op.setxattr(TEMP_POOL_ATTR.c_str(), pool_bl);
auto ret = rgw_rados_operate(dpp, ioctx_logging, target_obj_name, std::move(op), y);
if (ret < 0){
ldpp_dout(dpp, 1) << "ERROR: failed to add logging object entry " << obj_name
<< " to commit list object:" << target_obj_name
<< ". ret = " << ret << dendl;
return ret;
}
}
bufferlist empty_bl;
std::map<std::string, bufferlist> new_commit_list{{target_obj_name, empty_bl}};
librados::ObjectWriteOperation op;
op.create(false);
op.omap_set(new_commit_list);
auto ret = rgw_rados_operate(dpp, ioctx_logging, COMMIT_LIST_OBJECT_NAME,
std::move(op), y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to add entry " << target_obj_name
<< " to global bucket logging list object: "
<< COMMIT_LIST_OBJECT_NAME << ". ret = " << ret << dendl;
return ret;
}
ldpp_dout(dpp, 20) << "INFO: added entry " << target_obj_name
<< " to global bucket logging object: "
<< COMMIT_LIST_OBJECT_NAME << dendl;
return 0;
}
int list_pending_commit_objects(const DoutPrefixProvider* dpp,
rgw::sal::RadosStore* store,
const rgw::sal::Bucket* log_bucket,
const std::string& prefix,
std::set<std::string>& entries,
optional_yield y) {
auto& ioctx_logging = store->getRados()->get_logging_pool_ctx();
std::string target_obj_name = get_commit_list_name (log_bucket, prefix);
entries.clear();
constexpr auto max_chunk = 1024U;
std::string start_after;
bool more = true;
int rval;
while (more) {
librados::ObjectReadOperation op;
std::set <std::string> entries_chunk;
op.omap_get_keys2(start_after, max_chunk, &entries_chunk, &more, &rval);
const auto ret = rgw_rados_operate(dpp, ioctx_logging, target_obj_name,
std::move(op), nullptr, y);
if (ret == -ENOENT) {
// log commit list object was not created - nothing to do
return 0;
}
if (ret < 0) {
// TODO: do we need to check on rval as well as ret?
ldpp_dout(dpp, 1) << "ERROR: failed to read logging commit list "
<< target_obj_name << " ret: " << ret << dendl;
return ret;
}
entries.merge(entries_chunk);
if (more) {
start_after = *entries.rbegin();
}
}
return 0;
}
class BucketLoggingManager : public DoutPrefixProvider {
using Executor = boost::asio::io_context::executor_type;
bool m_shutdown = false;
static constexpr auto m_log_commits_update_period = std::chrono::milliseconds(10000); // 10s
static constexpr auto m_log_commits_update_retry = std::chrono::milliseconds(1000); // 1s
static constexpr auto m_log_commits_idle_sleep = std::chrono::milliseconds(5000); // 5s
const utime_t m_failover_time = utime_t(m_log_commits_update_period*9); // 90s
CephContext* const m_cct;
static constexpr auto COOKIE_LEN = 16;
const std::string m_lock_cookie;
const std::string m_lock_name = "bl_mgr_lock";
boost::asio::io_context m_io_context;
boost::asio::executor_work_guard<Executor> m_work_guard;
std::thread m_worker;
const SiteConfig& m_site;
rgw::sal::RadosStore* const m_rados_store;
private:
CephContext *get_cct() const override { return m_cct; }
unsigned get_subsys() const override { return dout_subsys; }
std::ostream& gen_prefix(std::ostream& out) const override {
return out << "rgw bucket_logging: ";
}
int parse_list_name(std::string list_obj_name, std::string &tenant_name,
std::string &bucket_name, std::string &bucket_id,
std::string &prefix) {
// <tenant_name>/<bucket_name>/<bucket_id>/<prefix>
size_t pstart = 0, pend = 0;
pend =list_obj_name.find('/');
if (pend == std::string::npos) {
return -EINVAL;
}
tenant_name = list_obj_name.substr(pstart, pend);
pstart = pend + 1;
pend =list_obj_name.find('/', pstart);
if (pend == std::string::npos) {
return -EINVAL;
}
bucket_name = list_obj_name.substr(pstart, pend - pstart);
if (bucket_name.empty()) {
return -EINVAL;
}
pstart = pend + 1;
pend =list_obj_name.find('/', pstart);
if (pend == std::string::npos) {
return -EINVAL;
}
bucket_id = list_obj_name.substr(pstart, pend - pstart);
if (bucket_id.empty()) {
return -EINVAL;
}
prefix = list_obj_name.substr(pend + 1);
/*
//TODO: Fix this
std::regex pattern(R"(([^/]+)/([^/]+)/([^/]+)/(.*))");
std::smatch matches;
if (std::regex_match(list_obj_name, matches, pattern)) {
tenant_name = matches[1].str();
bucket_name = matches[2].str();
bucket_id = matches[3].str();
prefix = matches[4].str();
} else {
return -EINVAL;
}
*/
return 0;
}
// read the list of commit lists from the global list object
int read_global_logging_list(commit_list_t& commits, optional_yield y) {
constexpr auto max_chunk = 1024U;
std::string start_after;
bool more = true;
int rval;
while (more) {
librados::ObjectReadOperation op;
commit_list_t commits_chunk;
op.omap_get_keys2(start_after, max_chunk, &commits_chunk, &more, &rval);
const auto ret = rgw_rados_operate(this, m_rados_store->getRados()->get_logging_pool_ctx(),
COMMIT_LIST_OBJECT_NAME, std::move(op),
nullptr, y);
if (ret == -ENOENT) {
// global commit list object was not created - nothing to do
return 0;
}
if (ret < 0) {
// TODO: do we need to check on rval as well as ret?
ldpp_dout(this, 5) << "ERROR: failed to read bucket logging global commit list. error: "
<< ret << dendl;
return ret;
}
commits.merge(commits_chunk);
if (more) {
start_after = *commits.rbegin();
}
}
return 0;
}
class tokens_waiter {
size_t pending_tokens = 0;
DoutPrefixProvider* const dpp;
ceph::async::yield_waiter<void> waiter;
public:
class token{
tokens_waiter* tw;
public:
token(const token& other) = delete;
token(token&& other) : tw(other.tw) {
other.tw = nullptr; // mark as moved
}
token& operator=(const token& other) = delete;
token(tokens_waiter* _tw) : tw(_tw) {
++tw->pending_tokens;
}
~token() {
if (!tw) {
return; // already moved
}
--tw->pending_tokens;
if (tw->pending_tokens == 0 && tw->waiter) {
tw->waiter.complete(boost::system::error_code{});
}
}
};
tokens_waiter(DoutPrefixProvider* _dpp) : dpp(_dpp) {}
tokens_waiter(const tokens_waiter& other) = delete;
tokens_waiter& operator=(const tokens_waiter& other) = delete;
void async_wait(boost::asio::yield_context yield) {
if (pending_tokens == 0) {
return;
}
ldpp_dout(dpp, 20) << "INFO: tokens waiter is waiting on "
<< pending_tokens << " tokens" << dendl;
boost::system::error_code ec;
waiter.async_wait(yield[ec]);
ldpp_dout(dpp, 20) << "INFO: tokens waiter finished waiting for all tokens" << dendl;
}
};
// processing of a specific entry
// return whether processing was successful (true) or not (false)
int process_entry(
const ConfigProxy& conf,
const std::string& entry,
const std::string& temp_obj_name,
const std::string& tenant_name,
const std::string& bucket_name,
const std::string& bucket_id,
const std::string& prefix,
const rgw_pool& obj_pool,
bool& bucket_deleted,
boost::asio::yield_context yield) {
std::unique_ptr<rgw::sal::Bucket> log_bucket;
rgw_bucket bucket = rgw_bucket{tenant_name, bucket_name, bucket_id};
int ret = m_rados_store->load_bucket(this, bucket, &log_bucket, yield);
if (ret < 0 && ret != -ENOENT) {
ldpp_dout(this, 1) << "ERROR: failed to load bucket : "
<< bucket_name << " id : " << bucket_id
<< ", error: " << ret << dendl;
return ret;
}
if (ret == 0) {
ldpp_dout(this, 20) << "INFO: loaded bucket : " << bucket_name
<< ", id: "<< bucket_id << dendl;
ret = log_bucket->commit_logging_object(entry, yield, this, prefix,
nullptr, false);
if (ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to commit logging object : "
<< entry << " , error: " << ret << dendl;
return ret;
}
ldpp_dout(this, 20) << "INFO: committed logging object : " << entry
<< " to bucket " << bucket_name
<< ", id: "<< bucket_id << dendl;
return 0;
}
// The log bucket has been deleted. Clean up pending objects.
// This is done because the bucket_deletion_cleanup only removes
// the current temp log objects.
bucket_deleted = true;
ldpp_dout(this, 20) << "INFO: log bucket : " << bucket_name
<< " no longer exists. Removing pending logging object "
<< temp_obj_name << " from pool " << obj_pool
<< dendl;
ret = rgw_delete_system_obj(this, m_rados_store->svc()->sysobj, obj_pool,
temp_obj_name, nullptr, yield);
if (ret < 0 && ret != -ENOENT) {
ldpp_dout(this, 1) << "ERROR: failed to delete pending logging object : "
<< temp_obj_name << " in pool " << obj_pool
<< " for deleted log bucket : " << bucket_name
<< " . ret = "<< ret << dendl;
return ret;
}
ldpp_dout(this, 20) << "INFO: Deleted pending logging object "
<< temp_obj_name << " from pool " << obj_pool
<< " for deleted log bucket : " << bucket_name
<< dendl;
return 0;
}
void async_sleep(boost::asio::yield_context yield, const std::chrono::milliseconds& duration) {
using Clock = ceph::coarse_mono_clock;
using Timer = boost::asio::basic_waitable_timer<Clock,
boost::asio::wait_traits<Clock>, Executor>;
Timer timer(m_io_context);
timer.expires_after(duration);
boost::system::error_code ec;
timer.async_wait(yield[ec]);
if (ec) {
ldpp_dout(this, 10) << "ERROR: async_sleep failed with error: "
<< ec.message() << dendl;
}
}
// unlock (lose ownership) list object
int unlock_list_object(librados::IoCtx& rados_ioctx,
const std::string& list_obj_name,
boost::asio::yield_context yield) {
librados::ObjectWriteOperation op;
op.assert_exists();
rados::cls::lock::unlock(&op, m_lock_name, m_lock_cookie);
const auto ret = rgw_rados_operate(this, rados_ioctx, list_obj_name,
std::move(op), yield);
if (ret == -ENOENT) {
ldpp_dout(this, 20) << "INFO: log commit list: " << list_obj_name
<< " was removed. Nothing to unlock." << dendl;
return 0;
}
if (ret == -EBUSY) {
ldpp_dout(this, 20) << "INFO: log commit list: " << list_obj_name
<< " already owned by another RGW. No need to unlock."
<< dendl;
return 0;
}
return ret;
}
int remove_commit_list(librados::IoCtx& rados_ioctx,
const std::string& commit_list_name,
optional_yield y) {
{
librados::ObjectWriteOperation op;
rados::cls::lock::assert_locked(&op, m_lock_name,
ClsLockType::EXCLUSIVE,
m_lock_cookie,
"" /*no tag*/);
op.remove();
auto ret = rgw_rados_operate(this, rados_ioctx, commit_list_name, std::move(op), y);
if (ret < 0 && ret != -ENOENT) {
ldpp_dout(this, 1) << "ERROR: failed to remove bucket logging commit list :"
<< commit_list_name << ". ret = " << ret << dendl;
return ret;
}
}
librados::ObjectWriteOperation op;
op.omap_rm_keys({commit_list_name});
auto ret = rgw_rados_operate(this, rados_ioctx, COMMIT_LIST_OBJECT_NAME,
std::move(op), y);
if (ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to remove entry " << commit_list_name
<< " from the global bucket logging list : "
<< COMMIT_LIST_OBJECT_NAME << ". ret = " << ret << dendl;
return ret;
}
ldpp_dout(this, 20) << "INFO: removed entry " << commit_list_name
<< " from the global bucket logging list : "
<< COMMIT_LIST_OBJECT_NAME << dendl;
return 0;
}
// processing of a specific target list
void process_commit_list(librados::IoCtx& rados_ioctx,
const std::string& list_obj_name,
boost::asio::yield_context yield) {
auto is_idle = false;
auto bucket_deleted = false;
auto skip_bucket_deletion = false;
const std::string start_marker;
std::string tenant_name, bucket_name, bucket_id, prefix;
int ret = parse_list_name(list_obj_name, tenant_name, bucket_name,
bucket_id, prefix);
if (ret) {
ldpp_dout(this, 1) << "ERROR: commit list name: " << list_obj_name
<< " is invalid. Processing will stop." << dendl;
return;
}
ldpp_dout(this, 20) << "INFO: parse commit list name: " << list_obj_name
<< ", bucket_name: " << bucket_name
<< ", bucket_id: " << bucket_id
<< ", tenant_name: " << tenant_name
<< ", prefix: " << prefix << dendl;
while (!m_shutdown) {
// if the list was empty the last time, sleep for idle timeout
if (is_idle) {
async_sleep(yield, m_log_commits_idle_sleep);
}
// Get the entries in the list after locking it
is_idle = true;
skip_bucket_deletion = false;
std::map<std::string, bufferlist> entries;
rgw_pool temp_data_pool;
auto total_entries = 0U;
{
librados::ObjectReadOperation op;
op.assert_exists();
bufferlist obl;
int rval;
bufferlist pool_obl;
int pool_rval;
constexpr auto max_chunk = 1024U;
std::string start_after;
bool more = true;
rados::cls::lock::assert_locked(&op, m_lock_name,
ClsLockType::EXCLUSIVE,
m_lock_cookie,
"" /*no tag*/);
op.omap_get_vals2(start_after, max_chunk, &entries, &more, &rval);
op.getxattr(TEMP_POOL_ATTR.c_str(), &pool_obl, &pool_rval);
// check ownership and list entries in one batch
auto ret = rgw_rados_operate(this, rados_ioctx, list_obj_name,
std::move(op), nullptr, yield);
if (ret == -ENOENT) {
// list object was deleted
ldpp_dout(this, 20) << "INFO: object: " << list_obj_name
<< " was removed. Processing will stop" << dendl;
return;
}
if (ret == -EBUSY) {
ldpp_dout(this, 10) << "WARNING: commit list : " << list_obj_name
<< " ownership moved to another daemon. Processing will stop"
<< dendl;
return;
}
if (ret < 0) {
ldpp_dout(this, 10) << "WARNING: failed to get list of entries in "
<< "and/or lock object: " << list_obj_name
<< ". error: " << ret << " (will retry)" << dendl;
continue;
}
if(pool_rval < 0) {
ldpp_dout(this, 10) << "WARNING: failed to get pool information"
<< "from commit list: " << list_obj_name << dendl;
return;
}
// Get temp logging object pool information - this is required for
// deleting the objects when the log bucket is deleted.
try {
auto p = pool_obl.cbegin();
decode(temp_data_pool, p);
} catch (buffer::error& err) {
ldpp_dout(this, 1) << "ERROR: failed to get pool information from object: "
<< list_obj_name << dendl;
return;
}
}
total_entries = entries.size();
if (total_entries == 0) {
// nothing in the list object
// Delete the list object if the bucket has been deleted
std::unique_ptr<rgw::sal::Bucket> log_bucket;
rgw_bucket bucket = rgw_bucket{tenant_name, bucket_name, bucket_id};
int ret = m_rados_store->load_bucket(this, bucket, &log_bucket, yield);
if (ret == -ENOENT) {
ldpp_dout(this, 20) << "ERROR: failed to load bucket : "
<< bucket_name << ", id : " << bucket_id
<< ", error: " << ret << dendl;
bucket_deleted = true;
}
} else {
// log when not idle
ldpp_dout(this, 20) << "INFO: found: " << total_entries
<< " entries in commit list: " << list_obj_name
<< dendl;
}
auto stop_processing = false;
std::set<std::string> remove_entries;
tokens_waiter tw(this);
for (auto const& [key, val] : entries) {
if (stop_processing) {
break;
}
std::string temp_obj_name = val.to_str();
ldpp_dout(this, 20) << "INFO: processing entry: " << key
<< ", value : " << temp_obj_name << dendl;
tokens_waiter::token token(&tw);
boost::asio::spawn(yield, std::allocator_arg, make_stack_allocator(),
[this, &is_idle, &list_obj_name, &remove_entries, &stop_processing,
&tenant_name, &bucket_name, &bucket_id, &prefix, token = std::move(token),
key, temp_obj_name, temp_data_pool, &bucket_deleted , &skip_bucket_deletion]
(boost::asio::yield_context yield) {
auto result =
process_entry(this->get_cct()->_conf, key, temp_obj_name, tenant_name,
bucket_name, bucket_id, prefix, temp_data_pool,
bucket_deleted, yield);
if (result == 0) {
ldpp_dout(this, 20) << "INFO: processing of entry: " << key
<< " from: " << list_obj_name
<< " was successful." << dendl;
remove_entries.insert(key);
is_idle = false;
return;
} else {
is_idle = true;
// Don't delete the bucket if we couldn't process the entry
// and the bucket has been deleted
skip_bucket_deletion = true;
ldpp_dout(this, 20) << "INFO: failed to process entry: " << key
<< " from: " << list_obj_name << dendl;
}
stop_processing = true;
}, [] (std::exception_ptr eptr) {
if (eptr) std::rethrow_exception(eptr);
});
}
if (!entries.empty()) {
// wait for all pending work to finish
tw.async_wait(yield);
}
if (bucket_deleted && !skip_bucket_deletion) {
ret = remove_commit_list(rados_ioctx, list_obj_name, yield);
if (ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to remove bucket logging commit list :"
<< list_obj_name << ". ret = " << ret << dendl;
return;
}
ldpp_dout(this, 10) << "INFO: bucket :" << bucket_name
<< ". was removed. processing will stop" << dendl;
return;
}
// delete all processed entries from list
if (!remove_entries.empty()) {
// Delete the entries even if the lock no longer belongs
// to this instance as we have processed the entries.
librados::ObjectWriteOperation op;
op.omap_rm_keys(remove_entries);
auto ret = rgw_rados_operate(this, rados_ioctx, list_obj_name, std::move(op), yield);
if (ret == -ENOENT) {
// list was deleted
ldpp_dout(this, 10) << "INFO: commit list " << list_obj_name
<< ". was removed. processing will stop" << dendl;
return;
}
if (ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to remove entries from commit list: "
<< list_obj_name << ". error: " << ret
<< ". This could cause some log records to be lost."
<< dendl;
return;
} else {
ldpp_dout(this, 20) << "INFO: removed entries from commit list: "
<< list_obj_name << dendl;
}
}
}
ldpp_dout(this, 5) << "INFO: BucketLogging manager stopped processing : "
<< list_obj_name << dendl;
}
// process all commit log objects
// find which of the commit log objects is owned by this daemon and process it
void process_global_logging_list(boost::asio::yield_context yield) {
auto has_error = false;
std::unordered_set<std::string> owned_commit_logs;
std::atomic<size_t> processed_list_count = 0;
std::vector<std::string> commit_list_gc;
std::mutex commit_list_gc_lock;
auto& rados_ioctx = m_rados_store->getRados()->get_logging_pool_ctx();
auto next_check_time = ceph::coarse_real_clock::zero();
while (!m_shutdown) {
// check if log commit list needs to be refreshed
if (ceph::coarse_real_clock::now() > next_check_time) {
next_check_time = ceph::coarse_real_clock::now() + m_log_commits_update_period;
const auto tp = ceph::coarse_real_time::clock::to_time_t(next_check_time);
ldpp_dout(this, 20) << "INFO: processing global logging commit list. next "
<< "processing will happen at: " << std::ctime(&tp)
<< dendl;
} else {
// short sleep duration to prevent busy wait when refreshing list
// or retrying after error
ldpp_dout(this, 20) << "INFO: processing global logging commit list. Sleep now." << dendl;
async_sleep(yield, m_log_commits_update_retry);
if (!has_error) {
// in case of error we will retry
continue;
}
}
std::set<std::string> commit_lists;
auto ret = read_global_logging_list(commit_lists, yield);
if (ret < 0) {
has_error = true;
ldpp_dout(this, 1) << "ERROR: failed to read global logging list. Retry. ret:"
<< ret << dendl;
continue;
}
for (const auto& list_obj_name : commit_lists) {
// try to lock the object to check if it is owned by this rgw
// or if ownership needs to be taken
ldpp_dout(this, 20) << "INFO: processing commit list: " << list_obj_name
<< dendl;
librados::ObjectWriteOperation op;
op.assert_exists();
rados::cls::lock::lock(&op, m_lock_name, ClsLockType::EXCLUSIVE,
m_lock_cookie, "" /*no tag*/,
"" /*no description*/, m_failover_time,
LOCK_FLAG_MAY_RENEW);
ret = rgw_rados_operate(this, rados_ioctx, list_obj_name, std::move(op), yield);
if (ret == -EBUSY) {
// lock is already taken by another RGW
ldpp_dout(this, 20) << "INFO: commit list: " << list_obj_name
<< " owned (locked) by another daemon" << dendl;
// if the list was owned by this RGW, processing should be stopped, would be deleted from list afterwards
continue;
}
if (ret == -ENOENT) {
// commit list is deleted - processing will stop the next time we try to read from it
ldpp_dout(this, 20) << "INFO: commit list: " << list_obj_name
<< " should not be locked - already deleted" << dendl;
continue;
}
if (ret < 0) {
// failed to lock for another reason, continue to process other lists
ldpp_dout(this, 10) << "ERROR: failed to lock commit list: "
<< list_obj_name << ". error: " << ret << dendl;
has_error = true;
continue;
}
// add the commit list to the list of owned commit_logs
if (owned_commit_logs.insert(list_obj_name).second) {
ldpp_dout(this, 20) << "INFO: " << list_obj_name << " now owned (locked) by this daemon" << dendl;
// start processing this list
boost::asio::spawn(make_strand(m_io_context), std::allocator_arg, make_stack_allocator(),
[this, &commit_list_gc, &commit_list_gc_lock, &rados_ioctx,
list_obj_name, &processed_list_count](boost::asio::yield_context yield) {
++processed_list_count;
process_commit_list(rados_ioctx, list_obj_name, yield);
// if list processing ended, it means that the list object was removed or not owned anymore
const auto ret = unlock_list_object(rados_ioctx, list_obj_name, yield);
if (ret < 0) {
ldpp_dout(this, 15) << "WARNING: failed to unlock commit list: "
<< list_obj_name << " with error: " << ret
<< " (ownership would still move if not renewed)"
<< dendl;
} else {
ldpp_dout(this, 20) << "INFO: commit list: " << list_obj_name
<< " not locked (ownership can move)" << dendl;
}
// mark it for deletion
std::lock_guard lock_guard(commit_list_gc_lock);
commit_list_gc.push_back(list_obj_name);
--processed_list_count;
ldpp_dout(this, 20) << "INFO: " << list_obj_name << " marked for removal" << dendl;
}, [this, list_obj_name] (std::exception_ptr eptr) {
ldpp_dout(this, 10) << "ERROR: " << list_obj_name << " processing failed" << dendl;
if (eptr) std::rethrow_exception(eptr);
});
} else {
ldpp_dout(this, 20) << "INFO: " << list_obj_name << " ownership (lock) renewed" << dendl;
}
}
// erase all list objects that were deleted
{
std::lock_guard lock_guard(commit_list_gc_lock);
std::for_each(commit_list_gc.begin(), commit_list_gc.end(), [this, &owned_commit_logs](const std::string& list_obj_name) {
owned_commit_logs.erase(list_obj_name);
ldpp_dout(this, 20) << "INFO: commit list object: " << list_obj_name << " was removed" << dendl;
});
commit_list_gc.clear();
}
}
while (processed_list_count > 0) {
ldpp_dout(this, 20) << "INFO: BucketLogging manager stopped. "
<< processed_list_count
<< " commit lists are still being processed" << dendl;
async_sleep(yield, m_log_commits_update_retry);
}
ldpp_dout(this, 5) << "INFO: BucketLogging manager stopped. Done processing all commit lists" << dendl;
}
public:
~BucketLoggingManager() {
}
void stop() {
ldpp_dout(this, 5) << "INFO: BucketLogging manager received stop signal. shutting down..." << dendl;
m_shutdown = true;
m_work_guard.reset();
if (m_worker.joinable()) {
// try graceful shutdown first
auto future = std::async(std::launch::async, [this]() {m_worker.join();});
if (future.wait_for(m_log_commits_update_retry*2) == std::future_status::timeout) {
// force stop if graceful shutdown takes too long
if (!m_io_context.stopped()) {
ldpp_dout(this, 5) << "INFO: force shutdown of BucketLogging Manager" << dendl;
m_io_context.stop();
}
m_worker.join();
}
}
ldpp_dout(this, 5) << "INFO: BucketLogging manager shutdown complete" << dendl;
}
void init() {
boost::asio::spawn(make_strand(m_io_context), std::allocator_arg, make_stack_allocator(),
[this](boost::asio::yield_context yield) {
process_global_logging_list(yield);
}, [] (std::exception_ptr eptr) {
if (eptr) std::rethrow_exception(eptr);
});
// start the worker threads to do the actual list processing
m_worker = std::thread([this]() {
ceph_pthread_setname("bucket-logging-worker");
try {
ldpp_dout(this, 20) << "INFO: bucket logging worker started" << dendl;
m_io_context.run();
ldpp_dout(this, 20) << "INFO: bucket logging worker ended" << dendl;
} catch (const std::exception& err) {
ldpp_dout(this, 10) << "ERROR: bucket logging worker failed with error: "
<< err.what() << dendl;
throw err;
}
});
ldpp_dout(this, 10) << "INFO: started bucket logging manager" << dendl;
}
BucketLoggingManager(CephContext* _cct, rgw::sal::RadosStore* store, const SiteConfig& site) :
m_cct(_cct),
m_lock_cookie(gen_rand_alphanumeric(m_cct, COOKIE_LEN)),
m_work_guard(boost::asio::make_work_guard(m_io_context)),
m_site(site),
m_rados_store(store)
{
ldpp_dout(this, 5) << "INFO: BucketLoggingManager() constructor" << dendl;
}
};
std::unique_ptr<BucketLoggingManager> s_manager;
bool init(const DoutPrefixProvider* dpp, rgw::sal::RadosStore* store,
const SiteConfig& site) {
if (s_manager) {
ldpp_dout(dpp, 1) << "ERROR: failed to init BucketLogging manager: already exists" << dendl;
return false;
}
// TODO: take conf from CephContext
ldpp_dout(dpp, 1) << "INFO: initialising BucketLogging manager" << dendl;
s_manager = std::make_unique<BucketLoggingManager>(dpp->get_cct(), store, site);
s_manager->init();
return true;
}
void shutdown() {
if (!s_manager) return;
s_manager->stop();
s_manager.reset();
}
} // namespace rgw::bucket_logging

View File

@ -0,0 +1,41 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab ft=cpp
#pragma once
#include <string>
// forward declarations
namespace rgw { class SiteConfig; }
namespace rgw::sal {
class RadosStore;
}
class DoutPrefixProvider;
namespace rgw::bucketlogging {
// initialize the bucket logging commit manager
bool init(const DoutPrefixProvider* dpp, rgw::sal::RadosStore* store,
const rgw::SiteConfig& site);
// shutdown the bucket logging commit manager
void shutdown();
int add_commit_target_entry(const DoutPrefixProvider* dpp,
rgw::sal::RadosStore* store,
const rgw::sal::Bucket* log_bucket,
const std::string& prefix,
const std::string& obj_name,
const std::string& tail_obj_name,
const rgw_pool& temp_data_pool,
optional_yield y);
int list_pending_commit_objects(const DoutPrefixProvider* dpp,
rgw::sal::RadosStore* store,
const rgw::sal::Bucket* log_bucket,
const std::string& prefix,
std::set<std::string>& entries,
optional_yield y);
}

View File

@ -57,6 +57,7 @@
#include "rgw_etag_verifier.h"
#include "rgw_worker.h"
#include "rgw_notify.h"
#include "rgw_bl_rados.h"
#include "rgw_http_errors.h"
#undef fork // fails to compile RGWPeriod::fork() below
@ -1144,6 +1145,10 @@ void RGWRados::finalize()
v1_topic_migration.stop();
}
if (run_bucket_logging_thread) {
rgw::bucketlogging::shutdown();
}
if (use_restore_thread) {
restore->stop_processor();
}
@ -1271,6 +1276,10 @@ int RGWRados::init_complete(const DoutPrefixProvider *dpp, optional_yield y)
if (ret < 0)
return ret;
ret = open_logging_pool_ctx(dpp);
if (ret < 0)
return ret;
pools_initialized = true;
if (use_gc) {
@ -1423,6 +1432,12 @@ int RGWRados::init_complete(const DoutPrefixProvider *dpp, optional_yield y)
index_completion_manager = new RGWIndexCompletionManager(this);
if (run_bucket_logging_thread) {
if (!rgw::bucketlogging::init(dpp, this->driver, *svc.site)) {
ldpp_dout(dpp, 0) << "ERROR: failed to initialize bucket logging manager" << dendl;
}
ldpp_dout(dpp, 0) << "INFO: initialized bucket logging manager" << dendl;
}
if (run_notification_thread) {
if (!rgw::notify::init(dpp, driver, *svc.site)) {
ldpp_dout(dpp, 0) << "ERROR: failed to initialize notification manager" << dendl;
@ -1443,7 +1458,6 @@ int RGWRados::init_complete(const DoutPrefixProvider *dpp, optional_yield y)
v1_topic_migration.start(1);
}
}
return ret;
}
@ -1547,6 +1561,11 @@ int RGWRados::open_notif_pool_ctx(const DoutPrefixProvider *dpp)
return rgw_init_ioctx(dpp, get_rados_handle(), svc.zone->get_zone_params().notif_pool, notif_pool_ctx, true, true);
}
int RGWRados::open_logging_pool_ctx(const DoutPrefixProvider *dpp)
{
return rgw_init_ioctx(dpp, get_rados_handle(), svc.zone->get_zone_params().bucket_logging_pool, logging_pool_ctx, true, true);
}
int RGWRados::open_pool_ctx(const DoutPrefixProvider *dpp, const rgw_pool& pool, librados::IoCtx& io_ctx,
bool mostly_omap, bool bulk)
{

View File

@ -364,6 +364,7 @@ class RGWRados
int open_objexp_pool_ctx(const DoutPrefixProvider *dpp);
int open_reshard_pool_ctx(const DoutPrefixProvider *dpp);
int open_notif_pool_ctx(const DoutPrefixProvider *dpp);
int open_logging_pool_ctx(const DoutPrefixProvider *dpp);
int open_pool_ctx(const DoutPrefixProvider *dpp, const rgw_pool& pool, librados::IoCtx& io_ctx,
bool mostly_omap, bool bulk);
@ -384,6 +385,7 @@ class RGWRados
bool run_sync_thread{false};
bool run_reshard_thread{false};
bool run_notification_thread{false};
bool run_bucket_logging_thread{false};
RGWMetaNotifier* meta_notifier{nullptr};
RGWDataNotifier* data_notifier{nullptr};
@ -459,6 +461,7 @@ protected:
librados::IoCtx objexp_pool_ctx;
librados::IoCtx reshard_pool_ctx;
librados::IoCtx notif_pool_ctx; // .rgw.notif
librados::IoCtx logging_pool_ctx; // .rgw.logging
bool pools_initialized{false};
@ -546,6 +549,11 @@ public:
return *this;
}
RGWRados& set_run_bucket_logging_thread(bool _run_bucket_logging_thread) {
run_bucket_logging_thread = _run_bucket_logging_thread;
return *this;
}
librados::IoCtx* get_lc_pool_ctx() {
return &lc_pool_ctx;
}
@ -561,6 +569,10 @@ public:
librados::IoCtx& get_notif_pool_ctx() {
return notif_pool_ctx;
}
librados::IoCtx& get_logging_pool_ctx() {
return logging_pool_ctx;
}
void set_context(CephContext *_cct) {
cct = _cct;

View File

@ -41,6 +41,7 @@
#include "rgw_aio_throttle.h"
#include "rgw_bucket.h"
#include "rgw_bucket_logging.h"
#include "rgw_bl_rados.h"
#include "rgw_lc.h"
#include "rgw_lc_tier.h"
#include "rgw_lc_tier.h"
@ -1096,6 +1097,7 @@ int RadosBucket::remove_topics(RGWObjVersionTracker* objv_tracker,
#define RGW_ATTR_COMMITTED_LOGGING_OBJ RGW_ATTR_PREFIX "committed-logging-obj"
#define RGW_ATTR_LOGGING_EC_POOL RGW_ATTR_PREFIX "logging-ec-pool"
int get_committed_logging_object(RadosStore* store,
const std::string& obj_name_oid,
@ -1140,10 +1142,94 @@ int set_committed_logging_object(RadosStore* store,
bufferlist bl;
bl.append(last_committed);
librados::ObjectWriteOperation op;
// if object does not exist, we should not create the attribute
op.assert_exists();
op.setxattr(RGW_ATTR_COMMITTED_LOGGING_OBJ, std::move(bl));
return rgw_rados_operate(dpp, io_ctx, obj_name_oid, std::move(op), y);
}
int get_logging_temp_object_pool (const DoutPrefixProvider *dpp,
RadosBucket* bucket,
RadosStore* rados_store,
const std::string& obj_name_oid,
rgw_pool& data_pool, bool& is_ec_pool, optional_yield y) {
int ret;
rgw_obj obj {bucket->get_key(), "dummy"};
if (!rados_store->getRados()->get_obj_data_pool(bucket->get_placement_rule(), obj, &data_pool)) {
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << bucket->get_key() <<
"' when writing logging object" << dendl;
return -EIO;
}
// Find out if the log bucket is on an EC pool
// Use an attribute on the logging name object instead of the bucket so
// it is not synced in a multi-site setup
librados::Rados* rados = rados_store->getRados()->get_rados_handle();
librados::IoCtx io_ctx;
if (ret = rgw_init_ioctx(dpp, rados, data_pool, io_ctx); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: get data pool ioctx for bucket '" << bucket->get_key() <<
"' when writing logging object. ret = " << ret << dendl;
return ret;
}
if (!io_ctx.is_valid()) {
ldpp_dout(dpp, 1) << "ERROR: invalid data pool ioctx for bucket '" << bucket->get_key() <<
"' when writing logging object" << dendl;
return ret;
}
is_ec_pool = false;
bufferlist bl;
librados::ObjectReadOperation op;
int rval;
op.getxattr(RGW_ATTR_LOGGING_EC_POOL, &bl, &rval);
ret = rgw_rados_operate(dpp, io_ctx, obj_name_oid, std::move(op), nullptr, y);
if (ret == 0) {
try {
ceph::decode(is_ec_pool, bl);
} catch (buffer::error& err) {
ldpp_dout(dpp, 1) << "ERROR: failed to decode " << RGW_ATTR_LOGGING_EC_POOL
<< " attr for bucket '" << bucket->get_key()
<< "'. error = " << err.what() << dendl;
return -EINVAL;
}
} else if (ret < 0){
// Try to find out if it is an EC pool
ret = rados->mon_command(
"{\"prefix\": \"osd pool get\", \"pool\": \"" +
data_pool.name + "\", \"var\": \"erasure_code_profile\"}",
{}, NULL, NULL);
if (ret == -EACCES) {
is_ec_pool = false;
} else if (ret == 0){
is_ec_pool = true;
} else {
ldpp_dout(dpp, 10) << __func__ << " ERROR: failed to find out if pool"
<< data_pool.name << " is erasure coded. ret = "
<< ret << dendl;
return ret;
}
bufferlist bl;
ceph::encode(is_ec_pool, bl);
librados::ObjectWriteOperation op;
// if object does not exist, we should not create the attribute
op.assert_exists();
op.setxattr(RGW_ATTR_LOGGING_EC_POOL, std::move(bl));
if (const int ret = rgw_rados_operate(dpp, io_ctx, obj_name_oid, std::move(op), y); ret < 0){
// Don't return an error as we know if it is an ec pool
ldpp_dout(dpp, 10) << "ERROR: failed to set is_ec_pool attr on :" << obj_name_oid
<< " ret: " << ret << dendl;
}
}
// If the target log bucket is on an EC pool, the temp
// logging object will be created in the default.rgw.log pool
if (is_ec_pool) {
data_pool = rados_store->svc()->zone->get_zone_params().bucket_logging_pool;
}
return 0;
}
int RadosBucket::get_logging_object_name(std::string& obj_name,
const std::string& prefix,
optional_yield y,
@ -1157,7 +1243,7 @@ int RadosBucket::get_logging_object_name(std::string& obj_name,
return -EIO;
}
bufferlist bl;
const int ret = rgw_get_system_obj(store->svc()->sysobj,
if (const int ret = rgw_get_system_obj(store->svc()->sysobj,
data_pool,
obj_name_oid,
bl,
@ -1166,15 +1252,18 @@ int RadosBucket::get_logging_object_name(std::string& obj_name,
y,
dpp,
nullptr,
nullptr);
if (ret < 0) {
if (ret == -ENOENT) {
ldpp_dout(dpp, 20) << "INFO: logging object name '" << obj_name_oid << "' not found. ret = " << ret << dendl;
return ret;
nullptr); ret < 0) {
if (ret != -ENOENT) {
ldpp_dout(dpp, 1) << "ERROR: failed to get logging object name from '" << obj_name_oid << "'. ret = " << ret << dendl;
} else {
ldpp_dout(dpp, 20) << "INFO: logging object name does not exist at '" << obj_name_oid << "'" << dendl;
}
ldpp_dout(dpp, 1) << "ERROR: failed to get logging object name from '" << obj_name_oid << "'. ret = " << ret << dendl;
return ret;
}
if (bl.length() == 0) {
ldpp_dout(dpp, 1) << "ERROR: logging object name at '" << obj_name_oid << "' is empty" << dendl;
return -ENODATA;
}
obj_name = bl.to_str();
return 0;
}
@ -1237,14 +1326,14 @@ std::string to_temp_object_name(const rgw::sal::Bucket* bucket, const std::strin
obj_name);
}
int RadosBucket::remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) {
int RadosBucket::remove_logging_object(const std::string& obj_name, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp) {
rgw_pool data_pool;
const rgw_obj head_obj{get_key(), obj_name};
const auto placement_rule = get_placement_rule();
if (!store->getRados()->get_obj_data_pool(placement_rule, head_obj, &data_pool)) {
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_key() <<
"' when deleting logging object" << dendl;
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
bool is_ec_pool;
auto ret = get_logging_temp_object_pool (dpp, this, store, obj_name_oid, data_pool, is_ec_pool, y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get temp data pool for bucket '" << get_key() <<
"' when deleting logging object: " << obj_name << ". ret: " << ret << dendl;
return -EIO;
}
@ -1260,7 +1349,7 @@ int RadosBucket::commit_logging_object(const std::string& obj_name,
optional_yield y,
const DoutPrefixProvider *dpp,
const std::string& prefix,
std::string* last_committed) {
std::string* last_committed, bool async) {
rgw_pool data_pool;
const rgw_obj head_obj{get_key(), obj_name};
const auto placement_rule = get_placement_rule();
@ -1270,9 +1359,10 @@ int RadosBucket::commit_logging_object(const std::string& obj_name,
"' when committing logging object" << dendl;
return -EIO;
}
int ret;
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
if (last_committed) {
if (const int ret = get_committed_logging_object(store,
if (ret = get_committed_logging_object(store,
obj_name_oid,
data_pool,
y,
@ -1290,11 +1380,34 @@ int RadosBucket::commit_logging_object(const std::string& obj_name,
}
const auto temp_obj_name = to_temp_object_name(this, obj_name);
rgw_pool temp_data_pool;
bool is_ec_pool = false;
ret = get_logging_temp_object_pool (dpp, this, store, obj_name_oid, temp_data_pool, is_ec_pool, y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '"
<< get_key() << "' when committing logging object: "
<< obj_name << ". ret: " << ret << dendl;
return -EIO;
}
if (async) {
ret = rgw::bucketlogging::add_commit_target_entry(dpp, store, this, prefix,
obj_name, temp_obj_name,
temp_data_pool, y);
if (ret < 0){
return ret;
}
ldpp_dout(dpp, 20) << "INFO: added logging object entry " << obj_name
<< " to commit list object." << dendl;
return 0;
}
std::map<string, bufferlist> obj_attrs;
ceph::real_time mtime;
bufferlist bl_data;
if (const auto ret = rgw_get_system_obj(store->svc()->sysobj,
data_pool,
if (ret = rgw_get_system_obj(store->svc()->sysobj,
temp_data_pool,
temp_obj_name,
bl_data,
nullptr,
@ -1303,13 +1416,43 @@ int RadosBucket::commit_logging_object(const std::string& obj_name,
dpp,
&obj_attrs,
nullptr); ret < 0) {
if (ret == -ENOENT) {
ldpp_dout(dpp, 5) << "WARNING: temporary logging object '" << temp_obj_name << "' does not exists" << dendl;
} else {
if (ret != -ENOENT) {
ldpp_dout(dpp, 1) << "ERROR: failed to read logging data when committing object '" << temp_obj_name
<< ". error: " << ret << dendl;
return ret;
}
mtime = ceph::real_time::clock::now();
ldpp_dout(dpp, 20) << "INFO: temporary logging object '" << temp_obj_name << "' does not exist. committing it empty" << dendl;
} else if (is_ec_pool) {
if (ret = rgw_put_system_obj(dpp, store->svc()->sysobj,
data_pool,
temp_obj_name,
bl_data,
true,
nullptr,
mtime,
y,
&obj_attrs); ret < 0){
if (ret == -EEXIST) {
ldpp_dout(dpp, 5) << "WARNING: race detected in committing logging object '" << temp_obj_name << dendl;
} else {
ldpp_dout(dpp, 1) << "ERROR: failed to write logging data when committing object '" << temp_obj_name
<< ". error: " << ret << dendl;
}
return ret;
}
ldpp_dout(dpp, 20) << "INFO: wrote logging data when committing object '" << temp_obj_name << dendl;
if (ret = rgw_delete_system_obj(dpp, store->svc()->sysobj,
temp_data_pool,
temp_obj_name,
nullptr,
y); ret < 0 && ret != -ENOENT) {
ldpp_dout(dpp, 1) << "ERROR: failed to delete temp logging object when "
<< "committing object '" << temp_obj_name
<< ". error: " << ret << dendl;
}
return ret;
}
uint64_t size = bl_data.length();
@ -1418,22 +1561,29 @@ void bucket_logging_completion(rados_completion_t completion, void* args) {
int RadosBucket::write_logging_object(const std::string& obj_name,
const std::string& record,
const std::string& prefix,
optional_yield y,
const DoutPrefixProvider *dpp,
bool async_completion) {
const auto temp_obj_name = to_temp_object_name(this, obj_name);
rgw_pool data_pool;
rgw_obj obj{get_key(), obj_name};
if (!store->getRados()->get_obj_data_pool(get_placement_rule(), obj, &data_pool)) {
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '" << get_key() <<
"' when writing logging object" << dendl;
bool is_ec_pool = false;
const auto obj_name_oid = bucketlogging::object_name_oid(this, prefix);
int ret = get_logging_temp_object_pool (dpp, this, store, obj_name_oid, data_pool, is_ec_pool, y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get data pool for bucket '"
<< get_key() << "' when writing logging object "
<< temp_obj_name << ", ret: " << ret << dendl;
return -EIO;
}
librados::IoCtx io_ctx;
if (const auto ret = rgw_init_ioctx(dpp, store->getRados()->get_rados_handle(), data_pool, io_ctx); ret < 0) {
if (const auto ret = rgw_init_ioctx(dpp, store->getRados()->get_rados_handle(), data_pool, io_ctx, true); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get IO context for logging object from data pool:" << data_pool.to_str() << dendl;
return -EIO;
}
bufferlist bl;
bl.append(record);
bl.append("\n");

View File

@ -803,9 +803,11 @@ class RadosBucket : public StoreBucket {
optional_yield y,
const DoutPrefixProvider *dpp,
RGWObjVersionTracker* objv_tracker) override;
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed) override;
int remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) override;
int write_logging_object(const std::string& obj_name, const std::string& record, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override;
int commit_logging_object(const std::string& obj_name, optional_yield y,
const DoutPrefixProvider *dpp, const std::string& prefix,
std::string* last_committed, bool async) override;
int remove_logging_object(const std::string& obj_name, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp) override;
int write_logging_object(const std::string& obj_name, const std::string& record, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override;
private:
int link(const DoutPrefixProvider* dpp, const rgw_owner& new_owner, optional_yield y, bool update_entrypoint = true, RGWObjVersionTracker* objv = nullptr);

View File

@ -118,6 +118,7 @@ struct RGWZoneParams : RGWSystemMetaObj {
rgw_pool account_pool;
rgw_pool group_pool;
rgw_pool dedup_pool;
rgw_pool bucket_logging_pool;
RGWAccessKey system_key;
@ -156,7 +157,7 @@ struct RGWZoneParams : RGWSystemMetaObj {
const std::string& get_compression_type(const rgw_placement_rule& placement_rule) const;
void encode(bufferlist& bl) const override {
ENCODE_START(17, 1, bl);
ENCODE_START(18, 1, bl);
encode(domain_root, bl);
encode(control_pool, bl);
encode(gc_pool, bl);
@ -187,11 +188,12 @@ struct RGWZoneParams : RGWSystemMetaObj {
encode(group_pool, bl);
encode(restore_pool, bl);
encode(dedup_pool, bl);
encode(bucket_logging_pool, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::const_iterator& bl) override {
DECODE_START(17, bl);
DECODE_START(18, bl);
decode(domain_root, bl);
decode(control_pool, bl);
decode(gc_pool, bl);
@ -279,6 +281,11 @@ struct RGWZoneParams : RGWSystemMetaObj {
} else {
dedup_pool = name + ".rgw.dedup";
}
if (struct_v >= 18) {
decode(bucket_logging_pool, bl);
} else {
bucket_logging_pool = log_pool.name + ":logging";
}
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;

View File

@ -90,6 +90,7 @@ extern "C" {
#include "driver/rados/rgw_bucket.h"
#include "driver/rados/rgw_sal_rados.h"
#include "driver/rados/rgw_bl_rados.h"
#include <iomanip>
@ -190,6 +191,7 @@ void usage()
cout << " bucket radoslist list rados objects backing bucket's objects\n";
cout << " bucket logging flush flush pending log records object of source bucket to the log bucket\n";
cout << " bucket logging info get info on bucket logging configuration on source bucket or list of sources in log bucket\n";
cout << " bucket logging list list the log objects pending commit for the source bucket\n";
cout << " bi get retrieve bucket index object entries\n";
cout << " bi put store bucket index object entries\n";
cout << " bi list list raw bucket index entries\n";
@ -725,6 +727,7 @@ enum class OPT {
BUCKET_RESYNC_ENCRYPTED_MULTIPART,
BUCKET_LOGGING_FLUSH,
BUCKET_LOGGING_INFO,
BUCKET_LOGGING_LIST,
POLICY,
LOG_LIST,
LOG_SHOW,
@ -974,6 +977,7 @@ static SimpleCmd::Commands all_cmds = {
{ "bucket resync encrypted multipart", OPT::BUCKET_RESYNC_ENCRYPTED_MULTIPART },
{ "bucket logging flush", OPT::BUCKET_LOGGING_FLUSH },
{ "bucket logging info", OPT::BUCKET_LOGGING_INFO },
{ "bucket logging list", OPT::BUCKET_LOGGING_LIST },
{ "policy", OPT::POLICY },
{ "log list", OPT::LOG_LIST },
{ "log show", OPT::LOG_SHOW },
@ -4620,6 +4624,7 @@ int main(int argc, const char **argv)
false,
false,
false,
false,
false, // No background tasks!
null_yield,
need_cache && g_conf()->rgw_cache_enabled,
@ -7816,25 +7821,26 @@ int main(int argc, const char **argv)
return 0;
}
// make sure that the logging source attribute is up-to-date
if (ret = rgw::bucketlogging::update_bucket_logging_sources(dpp(), target_bucket, bucket->get_key(), true, null_yield); ret < 0) {
cerr << "WARNING: failed to update logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
<< "' in logging target '" << target_bucket->get_key() << "'. error: " << cpp_strerror(ret) << std::endl;
}
std::string obj_name;
RGWObjVersionTracker objv_tracker;
ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, null_yield, dpp(), &objv_tracker);
if (ret < 0) {
cerr << "ERROR: failed to get pending logging object name from target bucket '" << configuration.target_bucket << "'" << std::endl;
if (ret < 0 && ret != -ENOENT) {
cerr << "ERROR: failed to get pending logging object name from target bucket '" << configuration.target_bucket <<
"'. error: " << cpp_strerror(-ret) << std::endl;
return -ret;
}
std::string old_obj;
const auto region = driver->get_zone()->get_zonegroup().get_api_name();
ret = rgw::bucketlogging::rollover_logging_object(configuration, target_bucket, obj_name, dpp(), region, bucket, null_yield, true, &objv_tracker, &old_obj);
ret = rgw::bucketlogging::rollover_logging_object(configuration, target_bucket, obj_name, dpp(), region, bucket, null_yield, true, &objv_tracker, false, &old_obj);
if (ret < 0) {
if (ret == -ENOENT) {
cerr << "WARNING: no pending logging object '" << obj_name << "'. nothing to flush";
ret = 0;
} else {
cerr << "ERROR: failed flush pending logging object '" << obj_name << "'";
}
cerr << " to target bucket '" << configuration.target_bucket << "'. "
<< " last committed object is '" << old_obj << "'" << std::endl;
cerr << "ERROR: failed to flush pending logging object '" << obj_name << "' to target bucket '" << configuration.target_bucket
<< "'. error: " << cpp_strerror(-ret) << std::endl;
return -ret;
}
cout << "flushed pending logging object '" << old_obj
@ -7883,6 +7889,55 @@ int main(int argc, const char **argv)
return 0;
}
if (opt_cmd == OPT::BUCKET_LOGGING_LIST) {
if (bucket_name.empty()) {
cerr << "ERROR: bucket not specified" << std::endl;
return EINVAL;
}
if (driver->get_name() != "rados") {
cerr << "ERROR: this command is only available with the RADOS driver." << std::endl;
return EINVAL;
}
int ret = init_bucket(tenant, bucket_name, bucket_id, &bucket);
if (ret < 0) {
return -ret;
}
rgw::bucketlogging::configuration configuration;
std::unique_ptr<rgw::sal::Bucket> target_bucket;
ret = rgw::bucketlogging::get_target_and_conf_from_source(dpp(),
driver, bucket.get(), tenant, configuration, target_bucket, null_yield);
if (ret < 0 && ret != -ENODATA) {
cerr << "ERROR: failed to get target bucket and logging conf from source bucket '"
<< bucket_name << "': " << cpp_strerror(-ret) << std::endl;
return -ret;
} else if (ret == -ENODATA) {
cerr << "ERROR: bucket '" << bucket_name << "' does not have logging enabled" << std::endl;
return 0;
}
std::string target_prefix = configuration.target_prefix;
std::set<std::string> entries;
ret = rgw::bucketlogging::list_pending_commit_objects(dpp(),
static_cast<rgw::sal::RadosStore*>(driver), target_bucket.get(),
target_prefix, entries, null_yield);
if (ret < 0) {
cerr << "ERROR: failed to get pending log entries for bucket '" << bucket_name
<< "': " << cpp_strerror(-ret) << std::endl;
return ret;
}
formatter->open_array_section("pending_logs");
for (auto &entry: entries) {
formatter->dump_string("log", entry);
}
formatter->close_section(); // objs
formatter->flush(cout);
return 0;
}
if (opt_cmd == OPT::LOG_LIST) {
// filter by date?
if (date.size() && date.size() != 10) {

View File

@ -258,7 +258,9 @@ int rgw::AppMain::init_storage()
run_quota,
run_sync,
g_conf().get_val<bool>("rgw_dynamic_resharding"),
true, true, null_yield, // run notification thread
true, // run notification thread
true, // run bucket-logging thread
true, null_yield,
g_conf()->rgw_cache_enabled);
if (!env.driver) {
return -EIO;

View File

@ -288,19 +288,19 @@ int new_logging_object(const configuration& conf,
int ret = target_bucket->set_logging_object_name(obj_name, conf.target_prefix, y, dpp, (old_name == std::nullopt), objv_tracker);
if (ret == -EEXIST || ret == -ECANCELED) {
if (ret = target_bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, nullptr); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of logging bucket '" <<
target_bucket_id << "' and prefix '" << conf.target_prefix << "', ret = " << ret << dendl;
return ret;
}
ldpp_dout(dpp, 20) << "INFO: name already set. got name of logging object '" << obj_name << "' of bucket '" <<
ldpp_dout(dpp, 20) << "INFO: name already set. got name of logging object '" << obj_name << "' of logging bucket '" <<
target_bucket_id << "' and prefix '" << conf.target_prefix << "'" << dendl;
return -ECANCELED;
} else if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to write name of logging object '" << obj_name << "' of bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: failed to write name of logging object '" << obj_name << "' of logging bucket '" <<
target_bucket_id << "'. ret = " << ret << dendl;
return ret;
}
ldpp_dout(dpp, 20) << "INFO: wrote name of logging object '" << obj_name << "' of bucket '" <<
ldpp_dout(dpp, 20) << "INFO: wrote name of logging object '" << obj_name << "' of logging bucket '" <<
target_bucket_id << "'" << dendl;
return 0;
}
@ -315,7 +315,7 @@ int commit_logging_object(const configuration& conf,
std::string target_tenant_name;
int ret = rgw_parse_url_bucket(conf.target_bucket, tenant_name, target_tenant_name, target_bucket_name);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to parse target bucket '" << conf.target_bucket << "' when commiting logging object, ret = "
ldpp_dout(dpp, 1) << "ERROR: failed to parse logging bucket '" << conf.target_bucket << "' when committing logging object, ret = "
<< ret << dendl;
return ret;
}
@ -324,26 +324,18 @@ int commit_logging_object(const configuration& conf,
ret = driver->load_bucket(dpp, target_bucket_id,
&target_bucket, y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get target logging bucket '" << target_bucket_id << "' when commiting logging object, ret = "
ldpp_dout(dpp, 1) << "ERROR: failed to get logging bucket '" << target_bucket_id << "' when committing logging object, ret = "
<< ret << dendl;
return ret;
}
return commit_logging_object(conf, target_bucket, dpp, y, last_committed);
}
int commit_logging_object(const configuration& conf,
const std::unique_ptr<rgw::sal::Bucket>& target_bucket,
const DoutPrefixProvider *dpp,
optional_yield y,
std::string* last_committed) {
std::string obj_name;
if (const int ret = target_bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, nullptr); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
return ret;
}
if (const int ret = target_bucket->commit_logging_object(obj_name, y, dpp, conf.target_prefix, last_committed); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to commit logging object '" << obj_name << "' of bucket '" <<
if (const int ret = target_bucket->commit_logging_object(obj_name, y, dpp, conf.target_prefix, last_committed, false); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to commit logging object '" << obj_name << "' of logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
return ret;
}
@ -359,34 +351,60 @@ int rollover_logging_object(const configuration& conf,
optional_yield y,
bool must_commit,
RGWObjVersionTracker* objv_tracker,
std::string* last_committed) {
bool async,
std::string* last_committed,
std::string* err_message) {
std::string target_bucket_name;
std::string target_tenant_name;
std::ignore = rgw_parse_url_bucket(conf.target_bucket, target_bucket->get_tenant(), target_tenant_name, target_bucket_name);
if (target_bucket_name != target_bucket->get_name() || target_tenant_name != target_bucket->get_tenant()) {
ldpp_dout(dpp, 1) << "ERROR: logging bucket name mismatch. conf= '" << conf.target_bucket <<
"', bucket= '" << target_bucket->get_key() << "'" << dendl;
return -EINVAL;
return -EINVAL; // this should never happen
}
const auto old_obj = obj_name;
const int ret = new_logging_object(conf, target_bucket, obj_name, dpp, region, source_bucket, y, old_obj, objv_tracker);
if (ret == -ECANCELED) {
ldpp_dout(dpp, 20) << "INFO: rollover already performed for object '" << old_obj << "' to logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
return 0;
} else if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to rollover object '" << old_obj << "' to logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
auto old_obj = obj_name.empty() ? std::nullopt : std::optional<std::string>(obj_name);
auto handle_error = [&dpp, &old_obj, &target_bucket, err_message](int ret) {
if (ret < 0) {
if (ret == -ECANCELED) {
ldpp_dout(dpp, 20) << "INFO: rollover already performed for logging object '" << old_obj << "' to logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
if (err_message) {
*err_message = fmt::format("Rollover already performed on logging bucket '{}'", target_bucket->get_name());
}
} else {
ldpp_dout(dpp, 1) << "ERROR: failed to rollover logging object '" << old_obj << "' to logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
if (err_message) {
*err_message = fmt::format("Failed to rollover logging object of logging bucket '{}'", target_bucket->get_name());
}
}
}
return ret;
};
if (const int ret = handle_error(new_logging_object(conf, target_bucket, obj_name, dpp, region, source_bucket, y, old_obj, objv_tracker)); ret < 0) {
return ret;
}
if (const int ret = target_bucket->commit_logging_object(old_obj, y, dpp, conf.target_prefix, last_committed); ret < 0) {
if (!old_obj) {
// first time logging old == new
old_obj = obj_name;
if (const int ret = handle_error(new_logging_object(conf, target_bucket, obj_name, dpp, region, source_bucket, y, old_obj, objv_tracker)); ret < 0) {
return ret;
}
}
if (const int ret = target_bucket->commit_logging_object(*old_obj, y, dpp, conf.target_prefix, last_committed, async); ret < 0) {
if (must_commit) {
if (err_message) {
*err_message = fmt::format("Failed to commit logging object of logging bucket '{}'", target_bucket->get_name());
}
return ret;
}
ldpp_dout(dpp, 5) << "WARNING: failed to commit object '" << old_obj << "' to logging bucket '" <<
target_bucket->get_key() << "'. ret = " << ret << dendl;
// we still want to write the new records to the new object even if commit failed
// will try to commit again next time
// TODO: should add commit retry mechanism
}
return 0;
}
@ -449,13 +467,17 @@ int log_record(rgw::sal::Driver* driver,
bool log_source_bucket) {
if (!s->bucket) {
ldpp_dout(dpp, 1) << "ERROR: only bucket operations are logged in bucket logging" << dendl;
return -EINVAL;
return -EINVAL; // this should never happen
}
auto set_journal_err = [&conf, s](const std::string& err_message) {
if (conf.logging_type == LoggingType::Journal) s->err.message = err_message;
};
std::string target_bucket_name;
std::string target_tenant_name;
int ret = rgw_parse_url_bucket(conf.target_bucket, s->bucket_tenant, target_tenant_name, target_bucket_name);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to parse target logging bucket '" << conf.target_bucket << "', ret = " << ret << dendl;
ldpp_dout(dpp, 1) << "ERROR: failed to parse logging bucket name '" << conf.target_bucket << "', ret = " << ret << dendl;
set_journal_err(fmt::format("Faild to parse logging bucket name '{}'", conf.target_bucket));
return ret;
}
const rgw_bucket target_bucket_id(target_tenant_name, target_bucket_name);
@ -463,21 +485,29 @@ int log_record(rgw::sal::Driver* driver,
ret = driver->load_bucket(dpp, target_bucket_id,
&target_bucket, y);
if (ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get target logging bucket '" << target_bucket_id << "'. ret = " << ret << dendl;
ldpp_dout(dpp, 1) << "ERROR: failed to load logging bucket '" << target_bucket_id << "'. ret = " << ret << dendl;
set_journal_err(fmt::format("Faild to load logging bucket '{}'", target_bucket_id.bucket_id));
return ret;
}
rgw::ARN target_resource_arn(target_bucket_id, conf.target_prefix);
if (ret = verify_target_bucket_policy(dpp, target_bucket.get(), target_resource_arn, s); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to verify target logging bucket policy for bucket '" << target_bucket->get_key() <<
"'. ret = " << ret << dendl;
return -EACCES;
std::string err_message;
if (ret = verify_target_bucket_policy(dpp, target_bucket.get(), target_resource_arn, s, &err_message); ret < 0) {
set_journal_err(err_message);
return ret;
}
if (ret = verify_target_bucket_attributes(dpp, target_bucket.get()); ret < 0) {
if (ret = verify_target_bucket_attributes(dpp, target_bucket.get(), &err_message); ret < 0) {
set_journal_err(err_message);
return ret;
}
// make sure that the logging source attribute is up-to-date
if (ret = update_bucket_logging_sources(dpp, target_bucket, s->bucket->get_key(), true, y); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: could not update bucket logging source '" <<
s->bucket->get_key() << "' in logging bucket '" << target_bucket_id << "' attribute, during record logging. ret = " << ret << dendl;
}
const auto region = driver->get_zone()->get_zonegroup().get_api_name();
std::string obj_name;
RGWObjVersionTracker objv_tracker;
@ -485,9 +515,10 @@ int log_record(rgw::sal::Driver* driver,
if (ret == 0) {
const auto time_to_commit = time_from_name(obj_name, dpp) + std::chrono::seconds(conf.obj_roll_time);
if (ceph::coarse_real_time::clock::now() > time_to_commit) {
ldpp_dout(dpp, 20) << "INFO: logging object '" << obj_name << "' exceeded its time, will be committed to bucket '" <<
ldpp_dout(dpp, 20) << "INFO: logging object '" << obj_name << "' exceeded its time, will be committed to logging bucket '" <<
target_bucket_id << "'" << dendl;
if (ret = rollover_logging_object(conf, target_bucket, obj_name, dpp, region, s->bucket, y, false, &objv_tracker, nullptr); ret < 0) {
if (ret = rollover_logging_object(conf, target_bucket, obj_name, dpp, region, s->bucket, y, false, &objv_tracker, true, nullptr, &err_message); ret < 0 && ret != -ECANCELED) {
set_journal_err(err_message);
return ret;
}
} else {
@ -497,19 +528,21 @@ int log_record(rgw::sal::Driver* driver,
// try to create the temporary log object for the first time
ret = new_logging_object(conf, target_bucket, obj_name, dpp, region, s->bucket, y, std::nullopt, &objv_tracker);
if (ret == 0) {
ldpp_dout(dpp, 20) << "INFO: first time logging for bucket '" << target_bucket_id << "' and prefix '" <<
ldpp_dout(dpp, 20) << "INFO: first time logging for logging bucket '" << target_bucket_id << "' and prefix '" <<
conf.target_prefix << "'" << dendl;
} else if (ret == -ECANCELED) {
ldpp_dout(dpp, 20) << "INFO: logging object '" << obj_name << "' already exists for bucket '" << target_bucket_id << "' and prefix" <<
ldpp_dout(dpp, 20) << "INFO: logging object '" << obj_name << "' already exists for logging bucket '" << target_bucket_id << "' and prefix" <<
conf.target_prefix << "'" << dendl;
} else {
ldpp_dout(dpp, 1) << "ERROR: failed to create logging object of bucket '" <<
target_bucket_id << "' and prefix '" << conf.target_prefix << "' for the first time. ret = " << ret << dendl;
ldpp_dout(dpp, 1) << "ERROR: failed to create first time logging object of logging bucket '" <<
target_bucket_id << "' and prefix '" << conf.target_prefix << "'. ret = " << ret << dendl;
set_journal_err(fmt::format("Faild create first time logging object of logging bucket '{}'", target_bucket->get_name()));
return ret;
}
} else {
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: failed to get name of logging object of logging bucket '" <<
target_bucket_id << "'. ret = " << ret << dendl;
set_journal_err(fmt::format("Faild to get name of logging object of logging bucket '{}'", target_bucket->get_name()));
return ret;
}
@ -544,7 +577,6 @@ int log_record(rgw::sal::Driver* driver,
bucket_name = full_bucket_name(s->bucket);
}
switch (conf.logging_type) {
case LoggingType::Standard:
record = fmt::format("{} {} [{:%d/%b/%Y:%H:%M:%S %z}] {} {} {} {} {} \"{} {}{}{} HTTP/1.1\" {} {} {} {} {} {} {} \"{}\" {} {} {} {} {} {} {} {} {}",
@ -592,14 +624,15 @@ int log_record(rgw::sal::Driver* driver,
case LoggingType::Any:
ldpp_dout(dpp, 1) << "ERROR: failed to format record when writing to logging object '" <<
obj_name << "' due to unsupported logging type" << dendl;
return -EINVAL;
return -EINVAL; // this should never happen
}
// get quota of the owner of the target bucket
RGWQuota user_quota;
if (ret = get_owner_quota_info(dpp, y, driver, target_bucket->get_owner(), user_quota); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get quota of owner of target logging bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: failed to get quota of owner of logging bucket '" <<
target_bucket_id << "' failed. ret = " << ret << dendl;
set_journal_err(fmt::format("Faild to get quota of owner of logging bucket '{}'", target_bucket->get_name()));
return ret;
}
// start with system default quota
@ -616,33 +649,39 @@ int log_record(rgw::sal::Driver* driver,
}
// verify there is enough quota to write the record
if (ret = target_bucket->check_quota(dpp, quota, record.length(), y); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: quota check on target logging bucket '" <<
ldpp_dout(dpp, 1) << "ERROR: quota check on logging bucket '" <<
target_bucket_id << "' failed. ret = " << ret << dendl;
set_journal_err(fmt::format("Quota check on logging bucket '{}' failed", target_bucket->get_name()));
return ret;
}
if (ret = target_bucket->write_logging_object(obj_name,
record,
conf.target_prefix,
y,
dpp,
async_completion); ret < 0 && ret != -EFBIG) {
ldpp_dout(dpp, 1) << "ERROR: failed to write record to logging object '" <<
obj_name << "'. ret = " << ret << dendl;
set_journal_err(fmt::format("Failed to write record to logging object of logging bucket {}", target_bucket->get_name()));
return ret;
}
if (ret == -EFBIG) {
ldpp_dout(dpp, 5) << "WARNING: logging object '" << obj_name << "' is full, will be committed to bucket '" <<
ldpp_dout(dpp, 5) << "WARNING: logging object '" << obj_name << "' is full, will be committed to logging bucket '" <<
target_bucket->get_key() << "'" << dendl;
if (ret = rollover_logging_object(conf, target_bucket, obj_name, dpp, region, s->bucket, y, true, &objv_tracker, nullptr); ret < 0 ) {
if (ret = rollover_logging_object(conf, target_bucket, obj_name, dpp, region, s->bucket, y, true, &objv_tracker, true, nullptr, &err_message); ret < 0 && ret != -ECANCELED) {
set_journal_err(err_message);
return ret;
}
if (ret = target_bucket->write_logging_object(obj_name,
record,
conf.target_prefix,
y,
dpp,
async_completion); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to write record to logging object '" <<
obj_name << "'. ret = " << ret << dendl;
set_journal_err(fmt::format("Failed to write record to logging object of logging bucket {}", target_bucket->get_name()));
return ret;
}
}
@ -720,7 +759,7 @@ int update_bucket_logging_sources(const DoutPrefixProvider* dpp, rgw::sal::Drive
std::unique_ptr<rgw::sal::Bucket> target_bucket;
const int ret = driver->load_bucket(dpp, target_bucket_id, &target_bucket, y);
if (ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get target logging bucket '" << target_bucket_id <<
ldpp_dout(dpp, 5) << "WARNING: failed to get logging bucket '" << target_bucket_id <<
"' in order to update logging sources. ret = " << ret << dendl;
return ret;
}
@ -757,8 +796,7 @@ int update_bucket_logging_sources(const DoutPrefixProvider* dpp, std::unique_ptr
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
<< "' for bucket '" << bucket->get_key() << "' when updating logging sources. error: " << err.what() << dendl;
}
ldpp_dout(dpp, 20) << "INFO: logging source '" << src_bucket_id << "' already " <<
(add ? "added to" : "removed from") << " bucket '" << bucket->get_key() << "'" << dendl;
// no change
return 0;
}, y);
}
@ -772,64 +810,71 @@ int bucket_deletion_cleanup(const DoutPrefixProvider* dpp,
// and also delete the object holding the pending object name
auto& attrs = bucket->get_attrs();
if (const auto iter = attrs.find(RGW_ATTR_BUCKET_LOGGING_SOURCES); iter != attrs.end()) {
source_buckets sources;
try {
source_buckets sources;
ceph::decode(sources, iter->second);
for (const auto& source : sources) {
std::unique_ptr<rgw::sal::Bucket> src_bucket;
if (const int ret = driver->load_bucket(dpp, source, &src_bucket, y); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging source bucket '" << source << "' for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
auto& src_attrs = src_bucket->get_attrs();
if (const auto iter = src_attrs.find(RGW_ATTR_BUCKET_LOGGING); iter != src_attrs.end()) {
configuration conf;
try {
auto bl_iter = iter->second.cbegin();
decode(conf, bl_iter);
std::string obj_name;
RGWObjVersionTracker objv;
if (const int ret = bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
"' during cleanup. ret = " << ret << dendl;
continue;
}
if (const int ret = bucket->remove_logging_object(obj_name, y, dpp); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to delete pending logging object '" << obj_name << "' for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
ldpp_dout(dpp, 20) << "INFO: successfully deleted pending logging object '" << obj_name << "' from deleted logging bucket '" <<
bucket->get_key() << "'" << dendl;
if (const int ret = bucket->remove_logging_object_name(conf.target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name from deleted logging bucket '" <<
bucket->get_key() << "'" << dendl;
} catch (buffer::error& err) {
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
<< "' of bucket '" << src_bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
}
}
}
} catch (buffer::error& err) {
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
<< "' for logging bucket '" << bucket->get_key() << "'. error: " << err.what() << dendl;
return -EIO;
}
// since we removed the attribute, we should not return error code from now on
// any retry, would find no attribute and return success
for (const auto& source : sources) {
std::unique_ptr<rgw::sal::Bucket> src_bucket;
if (const int ret = driver->load_bucket(dpp, source, &src_bucket, y); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging source bucket '" << source << "' for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
auto& src_attrs = src_bucket->get_attrs();
if (const auto iter = src_attrs.find(RGW_ATTR_BUCKET_LOGGING); iter != src_attrs.end()) {
configuration conf;
try {
auto bl_iter = iter->second.cbegin();
decode(conf, bl_iter);
} catch (buffer::error& err) {
ldpp_dout(dpp, 5) << "WARNING: failed to decode logging attribute '" << RGW_ATTR_BUCKET_LOGGING
<< "' of bucket '" << src_bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
continue;
}
std::string obj_name;
RGWObjVersionTracker objv;
if (const int ret = bucket->get_logging_object_name(obj_name, conf.target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
"' during cleanup. ret = " << ret << dendl;
continue;
}
if (const int ret = bucket->remove_logging_object_name(conf.target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name from deleted logging bucket '" <<
bucket->get_key() << "'" << dendl;
if (const int ret = bucket->remove_logging_object(obj_name, conf.target_prefix, y, dpp); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to delete pending logging object '" << obj_name << "' for logging bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
continue;
}
ldpp_dout(dpp, 20) << "INFO: successfully deleted pending logging object '" << obj_name << "' from deleted logging bucket '" <<
bucket->get_key() << "'" << dendl;
} else {
ldpp_dout(dpp, 5) << "WARNING: no logging attribute '" << RGW_ATTR_BUCKET_LOGGING
<< "' found in logging source bucket '" << src_bucket->get_key() << "' during cleanup" << dendl;
}
}
}
return source_bucket_cleanup(dpp, driver, bucket, false, y);
return source_bucket_cleanup(dpp, driver, bucket, false, y, nullptr);
}
int source_bucket_cleanup(const DoutPrefixProvider* dpp,
sal::Driver* driver,
sal::Bucket* bucket,
bool remove_attr,
optional_yield y) {
optional_yield y,
std::string* last_committed) {
std::optional<configuration> conf;
if (const int ret = retry_raced_bucket_write(dpp, bucket, [dpp, bucket, &conf, remove_attr, y] {
auto& attrs = bucket->get_attrs();
@ -842,7 +887,7 @@ int source_bucket_cleanup(const DoutPrefixProvider* dpp,
conf = std::move(tmp_conf);
} catch (buffer::error& err) {
ldpp_dout(dpp, 5) << "WARNING: failed to decode existing logging attribute '" << RGW_ATTR_BUCKET_LOGGING
<< "' of bucket '" << bucket->get_key() << "' during cleanup. error: " << err.what() << dendl;
<< "' of bucket '" << bucket->get_key() << "' during source cleanup. error: " << err.what() << dendl;
return -EIO;
}
if (remove_attr) {
@ -855,41 +900,75 @@ int source_bucket_cleanup(const DoutPrefixProvider* dpp,
}, y); ret < 0) {
if (remove_attr) {
ldpp_dout(dpp, 5) << "WARNING: failed to remove logging attribute '" << RGW_ATTR_BUCKET_LOGGING <<
"' from bucket '" << bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
"' from bucket '" << bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
}
return ret;
}
if (last_committed) {
last_committed->clear();
}
if (!conf) {
// no logging attribute found
return 0;
}
const auto& info = bucket->get_info();
if (const int ret = commit_logging_object(*conf, dpp, driver, info.bucket.tenant, y, nullptr); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: could not commit pending logging object of bucket '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
} else {
ldpp_dout(dpp, 20) << "INFO: successfully committed pending logging object of bucket '" << bucket->get_key() << "'" << dendl;
}
// since we removed the attribute, we should not return error code from now on
// any retry, would find no attribute and return success
rgw_bucket target_bucket_id;
const auto& info = bucket->get_info();
if (const int ret = get_bucket_id(conf->target_bucket, info.bucket.tenant, target_bucket_id); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to parse target logging bucket '" <<
conf->target_bucket << "' during cleanup. ret = " << ret << dendl;
ldpp_dout(dpp, 5) << "WARNING: failed to parse logging bucket '" <<
conf->target_bucket << "' during source cleanup. ret = " << ret << dendl;
return 0;
}
if (const int ret = update_bucket_logging_sources(dpp, driver, target_bucket_id, bucket->get_key(), false, y); ret < 0) {
std::unique_ptr<rgw::sal::Bucket> target_bucket;
const int ret = driver->load_bucket(dpp, target_bucket_id, &target_bucket, y);
if (ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging bucket '" << target_bucket_id <<
"' when doing source cleanup. ret = " << ret << dendl;
return 0;
}
if (const int ret = update_bucket_logging_sources(dpp, target_bucket, bucket->get_key(), false, y); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: could not update bucket logging source '" <<
bucket->get_key() << "' during cleanup. ret = " << ret << dendl;
bucket->get_key() << "' in logging bucket '" << target_bucket_id << "' attribute, during source cleanup. ret = " << ret << dendl;
}
std::string obj_name;
RGWObjVersionTracker objv;
if (const int ret = target_bucket->get_logging_object_name(obj_name, conf->target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to get logging object name for logging bucket '" << bucket->get_key() <<
"' during source cleanup. ret = " << ret << dendl;
// if name cannot be fetched, we should not commit or remove the object holding the name
// it is better to leak an object than to cause a possible data loss
return 0;
}
ldpp_dout(dpp, 20) << "INFO: successfully updated bucket logging source '" <<
bucket->get_key() << "' during cleanup"<< dendl;
if (const int ret = target_bucket->remove_logging_object_name(conf->target_prefix, y, dpp, &objv); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: failed to delete object holding bucket logging object name for bucket '" <<
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
// this could be because of a race someone else trying to commit the object
// (another bucket cleanup with shared prefix, rollover or an explicit commit)
// and since committing the object twice will cause data loss, we should not try to commit it here
return 0;
}
ldpp_dout(dpp, 20) << "INFO: successfully deleted object holding bucket logging object name for bucket '" <<
bucket->get_key() << "' during source cleanup" << dendl;
// since the object holding the name was deleted, we cannot fetch the last commited name from it
if (const int ret = target_bucket->commit_logging_object(obj_name, y, dpp, conf->target_prefix, nullptr, false); ret < 0) {
ldpp_dout(dpp, 5) << "WARNING: could not commit pending logging object of bucket '" <<
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
return 0;
}
ldpp_dout(dpp, 20) << "INFO: successfully committed pending logging object of bucket '" <<
bucket->get_key() << "' during source cleanup. ret = " << ret << dendl;
if (last_committed) {
*last_committed = obj_name;
}
return 0;
}
int verify_target_bucket_policy(const DoutPrefixProvider* dpp,
rgw::sal::Bucket* target_bucket,
const rgw::ARN& target_resource_arn,
req_state* s) {
req_state* s,
std::string* err_message) {
// verify target permissions for bucket logging
// this is implementing the policy based permission granting from:
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html#grant-log-delivery-permissions-general
@ -898,6 +977,9 @@ int verify_target_bucket_policy(const DoutPrefixProvider* dpp,
const auto policy_it = target_attrs.find(RGW_ATTR_IAM_POLICY);
if (policy_it == target_attrs.end()) {
ldpp_dout(dpp, 1) << "ERROR: logging bucket '" << target_bucket_id << "' must have bucket policy to allow logging" << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' must have policy to allow logging", target_bucket->get_name());
}
return -EACCES;
}
try {
@ -914,33 +996,48 @@ int verify_target_bucket_policy(const DoutPrefixProvider* dpp,
"' must have a bucket policy that allows logging service principal to put objects in the following resource ARN: '" <<
target_resource_arn.to_string() << "' from source bucket ARN: '" << source_bucket_arn <<
"' and source account: '" << source_account << "'" << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' policy does not allow logging", target_bucket->get_name());
}
return -EACCES;
}
} catch (const rgw::IAM::PolicyParseException& err) {
ldpp_dout(dpp, 1) << "ERROR: failed to parse logging bucket '" << target_bucket_id <<
"' policy. error: " << err.what() << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' has invalid policy", target_bucket->get_name());
}
return -EACCES;
}
return 0;
}
int verify_target_bucket_attributes(const DoutPrefixProvider* dpp, rgw::sal::Bucket* target_bucket) {
int verify_target_bucket_attributes(const DoutPrefixProvider* dpp, rgw::sal::Bucket* target_bucket, std::string* err_message) {
const auto& target_info = target_bucket->get_info();
if (target_info.requester_pays) {
// target bucket must not have requester pays set on it
ldpp_dout(dpp, 1) << "ERROR: logging target bucket '" << target_bucket->get_key() << "', is configured with requester pays" << dendl;
ldpp_dout(dpp, 1) << "ERROR: logging bucket '" << target_bucket->get_key() << "', is configured with requester pays" << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' is configured with requester pays", target_bucket->get_name());
}
return -EINVAL;
}
const auto& target_attrs = target_bucket->get_attrs();
if (target_attrs.find(RGW_ATTR_BUCKET_LOGGING) != target_attrs.end()) {
// target bucket must not have logging set on it
ldpp_dout(dpp, 1) << "ERROR: logging target bucket '" << target_bucket->get_key() << "', is configured with bucket logging" << dendl;
ldpp_dout(dpp, 1) << "ERROR: logging bucket '" << target_bucket->get_key() << "', is configured with bucket logging" << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' is configured with bucket logging", target_bucket->get_name());
}
return -EINVAL;
}
if (target_attrs.find(RGW_ATTR_BUCKET_ENCRYPTION_POLICY) != target_attrs.end()) {
// verify target bucket does not have encryption
ldpp_dout(dpp, 1) << "ERROR: logging target bucket '" << target_bucket->get_key() << "', is configured with encryption" << dendl;
ldpp_dout(dpp, 1) << "ERROR: logging bucket '" << target_bucket->get_key() << "', is configured with encryption" << dendl;
if (err_message) {
*err_message = fmt::format("Logging bucket '{}' is configured with encryption", target_bucket->get_name());
}
return -EINVAL;
}
return 0;
@ -973,13 +1070,13 @@ int get_target_and_conf_from_source(
rgw_bucket target_bucket_id;
if (const int ret = get_bucket_id(configuration.target_bucket, tenant, target_bucket_id); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to parse target bucket '" << configuration.target_bucket << "', ret = " << ret << dendl;
ldpp_dout(dpp, 1) << "ERROR: failed to parse logging bucket '" << configuration.target_bucket << "', ret = " << ret << dendl;
return ret;
}
if (const int ret = driver->load_bucket(dpp, target_bucket_id,
&target_bucket, y); ret < 0) {
ldpp_dout(dpp, 1) << "ERROR: failed to get target bucket '" << target_bucket_id << "', ret = " << ret << dendl;
ldpp_dout(dpp, 1) << "ERROR: failed to get logging bucket '" << target_bucket_id << "', ret = " << ret << dendl;
return ret;
}
return 0;

View File

@ -173,6 +173,7 @@ int log_record(rgw::sal::Driver* driver,
// and create a new pending log object
// if "must_commit" is "false" the function will return success even if the pending log object was not committed
// if "last_committed" is not null, it will be set to the name of the last committed object
// optional error message is returned by reference
int rollover_logging_object(const configuration& conf,
const std::unique_ptr<rgw::sal::Bucket>& bucket,
std::string& obj_name,
@ -182,28 +183,9 @@ int rollover_logging_object(const configuration& conf,
optional_yield y,
bool must_commit,
RGWObjVersionTracker* objv_tracker,
std::string* last_committed);
// commit the pending log object to the log bucket
// use this for cleanup, when new pending object is not needed
// and target bucket is known
// if "last_committed" is not null, it will be set to the name of the last committed object
int commit_logging_object(const configuration& conf,
const std::unique_ptr<rgw::sal::Bucket>& target_bucket,
const DoutPrefixProvider *dpp,
optional_yield y,
std::string* last_committed);
// commit the pending log object to the log bucket
// use this for cleanup, when new pending object is not needed
// and target bucket shoud be loaded based on the configuration
// if "last_committed" is not null, it will be set to the name of the last committed object
int commit_logging_object(const configuration& conf,
const DoutPrefixProvider *dpp,
rgw::sal::Driver* driver,
const std::string& tenant_name,
optional_yield y,
std::string* last_committed);
bool async,
std::string* last_committed,
std::string* err_message = nullptr);
// return the oid of the object holding the name of the temporary logging object
// bucket - log bucket
@ -251,24 +233,31 @@ int bucket_deletion_cleanup(const DoutPrefixProvider* dpp,
// in addition:
// any pending log objects should be comitted to the log bucket
// and the log bucket should be updated to remove the bucket as a source
// if "last_committed" is not null, it will be set to the name of the last committed object
int source_bucket_cleanup(const DoutPrefixProvider* dpp,
sal::Driver* driver,
sal::Bucket* bucket,
bool remove_attr,
optional_yield y);
optional_yield y,
std::string* last_committed);
// verify that the target bucket has the correct policy to allow the source bucket to log to it
// note that this function adds entries to the request state environment
// optional error message is returned by reference
int verify_target_bucket_policy(const DoutPrefixProvider* dpp,
rgw::sal::Bucket* target_bucket,
const rgw::ARN& target_resource_arn,
req_state* s);
req_state* s,
std::string* err_message = nullptr);
// verify that target bucket does not have:
// - bucket logging
// - requester pays
// - encryption
int verify_target_bucket_attributes(const DoutPrefixProvider* dpp, rgw::sal::Bucket* target_bucket);
// optional error message is returned by reference
int verify_target_bucket_attributes(const DoutPrefixProvider* dpp,
rgw::sal::Bucket* target_bucket,
std::string* err_message = nullptr);
// given a source bucket this function is parsing the configuration object
// extracting the target bucket and load it

View File

@ -1255,7 +1255,7 @@ struct req_info {
meta_map_t crypt_attribute_map;
std::string host;
const char *method;
const char *method = nullptr;
std::string script_uri;
std::string request_uri;
std::string request_uri_aws4;

View File

@ -105,7 +105,7 @@ int main(const int argc, const char **argv)
exit(1);
}
driver = DriverManager::get_storage(&dp, g_ceph_context, cfg, context_pool, site, false, false, false, false, false, false, false, true, null_yield);
driver = DriverManager::get_storage(&dp, g_ceph_context, cfg, context_pool, site, false, false, false, false, false, false, false, false, true, null_yield);
if (!driver) {
std::cerr << "couldn't init storage provider" << std::endl;
return EIO;

View File

@ -309,9 +309,15 @@ public:
}
virtual const char* name() const = 0;
virtual RGWOpType get_type() { return RGW_OP_UNKNOWN; }
virtual std::string canonical_name() const { return fmt::format("REST.{}.{}", s->info.method, name()); }
virtual std::string canonical_name() const {
return fmt::format("REST.{}.{}",
s->info.method != nullptr ? s->info.method : "UNKNOWN",
name());
}
// by default we log all bucket operations
virtual bool always_do_bucket_logging() const { return s->bucket != nullptr; }
virtual bool always_do_bucket_logging() const {
return s->bucket != nullptr;
}
virtual uint32_t op_mask() { return 0; }
@ -482,6 +488,12 @@ public:
virtual int send_response_data(bufferlist& bl, off_t ofs, off_t len) = 0;
const char* name() const override { return "get_obj"; }
std::string canonical_name() const override {
if (get_torrent) {
return fmt::format("REST.{}.TORRENT", s->info.method);
}
return fmt::format("REST.{}.OBJECT", s->info.method);
}
RGWOpType get_type() override { return RGW_OP_GET_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
virtual bool need_object_expiration() { return false; }
@ -523,6 +535,7 @@ class RGWGetObjTags : public RGWOp {
virtual void send_response_data(bufferlist& bl) = 0;
const char* name() const override { return "get_obj_tags"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
RGWOpType get_type() override { return RGW_OP_GET_OBJ_TAGGING; }
@ -538,6 +551,7 @@ class RGWPutObjTags : public RGWOp {
virtual void send_response() override = 0;
virtual int get_params(optional_yield y) = 0;
const char* name() const override { return "put_obj_tags"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
RGWOpType get_type() override { return RGW_OP_PUT_OBJ_TAGGING; }
@ -550,6 +564,7 @@ class RGWDeleteObjTags: public RGWOp {
void execute(optional_yield y) override;
const char* name() const override { return "delete_obj_tags"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
RGWOpType get_type() override { return RGW_OP_DELETE_OBJ_TAGGING;}
};
@ -565,6 +580,7 @@ public:
virtual void send_response_data(bufferlist& bl) = 0;
const char* name() const override { return "get_bucket_tags"; }
std::string canonical_name() const override { return fmt::format("REST.{}.TAGGING", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_TAGGING; }
};
@ -580,6 +596,7 @@ public:
virtual void send_response() override = 0;
virtual int get_params(const DoutPrefixProvider *dpp, optional_yield y) = 0;
const char* name() const override { return "put_bucket_tags"; }
std::string canonical_name() const override { return fmt::format("REST.{}.TAGGING", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_TAGGING; }
};
@ -605,6 +622,7 @@ public:
virtual void send_response_data() = 0;
const char* name() const override { return "get_bucket_replication"; }
std::string canonical_name() const override { return fmt::format("REST.{}.REPLICATION", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_REPLICATION; }
};
@ -620,6 +638,7 @@ public:
virtual void send_response() override = 0;
virtual int get_params(optional_yield y) = 0;
const char* name() const override { return "put_bucket_replication"; }
std::string canonical_name() const override { return fmt::format("REST.{}.REPLICATION", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_REPLICATION; }
};
@ -633,6 +652,7 @@ public:
void execute(optional_yield y) override;
const char* name() const override { return "delete_bucket_replication"; }
std::string canonical_name() const override { return fmt::format("REST.{}.REPLICATION", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET_REPLICATION;}
};
@ -708,6 +728,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "bulk_delete"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BULK_DELETE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_BULK_DELETE; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
dmc::client_id dmclock_client() override { return dmc::client_id::data; }
@ -779,6 +800,7 @@ public:
void execute(optional_yield y) override;
const char* name() const override { return "bulk_upload"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BULK_UPLOAD", s->info.method); }
RGWOpType get_type() override {
return RGW_OP_BULK_UPLOAD;
@ -901,6 +923,7 @@ public:
virtual bool supports_account_metadata() { return false; }
const char* name() const override { return "list_buckets"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKETS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_LIST_BUCKETS; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
}; // class RGWListBuckets
@ -985,6 +1008,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "list_bucket"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
RGWOpType get_type() override { return RGW_OP_LIST_BUCKET; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
virtual bool need_container_stats() { return false; }
@ -999,6 +1023,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_bucket_location"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LOCATION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_LOCATION; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1017,6 +1042,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_bucket_versioning"; }
std::string canonical_name() const override { return fmt::format("REST.{}.VERSIONING", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_VERSIONING; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1045,6 +1071,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "set_bucket_versioning"; }
std::string canonical_name() const override { return fmt::format("REST.{}.VERSIONING", s->info.method); }
RGWOpType get_type() override { return RGW_OP_SET_BUCKET_VERSIONING; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1059,6 +1086,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_bucket_website"; }
std::string canonical_name() const override { return fmt::format("REST.{}.WEBSITE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_WEBSITE; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1078,6 +1106,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "set_bucket_website"; }
std::string canonical_name() const override { return fmt::format("REST.{}.WEBSITE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_SET_BUCKET_WEBSITE; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1092,6 +1121,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "delete_bucket_website"; }
std::string canonical_name() const override { return fmt::format("REST.{}.WEBSITE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_SET_BUCKET_WEBSITE; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1141,6 +1171,7 @@ class RGWCreateBucket : public RGWOp {
virtual int get_params(optional_yield y) { return 0; }
void send_response() override = 0;
const char* name() const override { return "create_bucket"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
RGWOpType get_type() override { return RGW_OP_CREATE_BUCKET; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1158,6 +1189,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "delete_bucket"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
};
@ -1327,6 +1359,10 @@ public:
virtual int get_data(bufferlist& bl) = 0;
void send_response() override = 0;
const char* name() const override { return "put_obj"; }
std::string canonical_name() const override {
const bool multipart = !multipart_upload_id.empty();
return fmt::format("REST.{}.{}", s->info.method, multipart ? "PART" : "OBJECT");
}
RGWOpType get_type() override { return RGW_OP_PUT_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
dmc::client_id dmclock_client() override { return dmc::client_id::data; }
@ -1379,6 +1415,7 @@ public:
virtual int get_data(ceph::bufferlist& bl, bool& again) = 0;
void send_response() override = 0;
const char* name() const override { return "post_obj"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_POST_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
dmc::client_id dmclock_client() override { return dmc::client_id::data; }
@ -1485,6 +1522,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "restore_obj"; }
std::string canonical_name() const override { return fmt::format("REST.{}.RESTORE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_RESTORE_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1522,6 +1560,7 @@ public:
virtual int get_params(optional_yield y) { return 0; }
void send_response() override = 0;
const char* name() const override { return "delete_obj"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
virtual bool need_object_expiration() { return false; }
@ -1619,6 +1658,7 @@ public:
virtual void send_partial_response(off_t ofs) {}
void send_response() override = 0;
const char* name() const override { return "copy_obj"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_COPY_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
dmc::client_id dmclock_client() override { return dmc::client_id::data; }
@ -1637,6 +1677,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_acls"; }
std::string canonical_name() const override { return fmt::format("REST.{}.ACL", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_ACLS; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1658,6 +1699,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "put_acls"; }
std::string canonical_name() const override { return fmt::format("REST.{}.ACL", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_ACLS; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1702,6 +1744,7 @@ public:
void execute(optional_yield y) override;
void send_response() override = 0;
const char* name() const override { return "get_obj_attrs"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_ATTRIBUTES", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_OBJ_ATTRS; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
}; /* RGWGetObjAttrs */
@ -1719,6 +1762,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_lifecycle"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_LC; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1751,6 +1795,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "put_lifecycle"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_LC; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1764,6 +1809,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "delete_lifecycle"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_LC; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1779,6 +1825,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_cors"; }
std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_CORS; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1798,6 +1845,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "put_cors"; }
std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_CORS; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1813,6 +1861,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "delete_cors"; }
std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_CORS; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1849,6 +1898,7 @@ public:
int verify_permission(optional_yield y) override;
void execute(optional_yield y) override;
const char* name() const override { return "put_bucket_encryption"; }
std::string canonical_name() const override { return fmt::format("REST.{}.ENCRYPTION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_ENCRYPTION; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1863,6 +1913,7 @@ public:
int verify_permission(optional_yield y) override;
void execute(optional_yield y) override;
const char* name() const override { return "get_bucket_encryption"; }
std::string canonical_name() const override { return fmt::format("REST.{}.ENCRYPTION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_ENCRYPTION; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1877,6 +1928,7 @@ public:
int verify_permission(optional_yield y) override;
void execute(optional_yield y) override;
const char* name() const override { return "delete_bucket_encryption"; }
std::string canonical_name() const override { return fmt::format("REST.{}.ENCRYPTION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET_ENCRYPTION; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1894,6 +1946,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "get_request_payment"; }
std::string canonical_name() const override { return fmt::format("REST.{}.REQUEST_PAYMENT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_REQUEST_PAYMENT; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -1913,6 +1966,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "set_request_payment"; }
std::string canonical_name() const override { return fmt::format("REST.{}.REQUEST_PAYMENT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_SET_REQUEST_PAYMENT; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -1941,6 +1995,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "init_multipart"; }
std::string canonical_name() const override { return fmt::format("REST.{}.UPLOADS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_INIT_MULTIPART; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
virtual int prepare_encryption(std::map<std::string, bufferlist>& attrs) { return 0; }
@ -1976,6 +2031,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "complete_multipart"; }
std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
RGWOpType get_type() override { return RGW_OP_COMPLETE_MULTIPART; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
bool always_do_bucket_logging() const override { return false; }
@ -1993,6 +2049,7 @@ public:
void send_response() override = 0;
const char* name() const override { return "abort_multipart"; }
std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
RGWOpType get_type() override { return RGW_OP_ABORT_MULTIPART; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
};
@ -2022,6 +2079,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "list_multipart"; }
std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
RGWOpType get_type() override { return RGW_OP_LIST_MULTIPART; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -2061,6 +2119,7 @@ public:
virtual int get_params(optional_yield y) = 0;
void send_response() override = 0;
const char* name() const override { return "list_bucket_multiparts"; }
std::string canonical_name() const override { return fmt::format("REST.{}.UPLOADS", s->info.method); }
RGWOpType get_type() override { return RGW_OP_LIST_BUCKET_MULTIPARTS; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -2161,6 +2220,7 @@ public:
int ret) = 0;
virtual void end_response() = 0;
const char* name() const override { return "multi_object_delete"; }
std::string canonical_name() const override { return fmt::format("REST.{}.DELETE_MULTI_OBJECT", s->info.method); }
RGWOpType get_type() override { return RGW_OP_DELETE_MULTI_OBJ; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
@ -2471,6 +2531,7 @@ public:
void execute(optional_yield y) override;
int get_params(optional_yield y);
const char* name() const override { return "put_bucket_policy"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKETPOLICY", s->info.method); }
RGWOpType get_type() override {
return RGW_OP_PUT_BUCKET_POLICY;
}
@ -2487,6 +2548,7 @@ public:
}
void execute(optional_yield y) override;
const char* name() const override { return "get_bucket_policy"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKETPOLICY", s->info.method); }
RGWOpType get_type() override {
return RGW_OP_GET_BUCKET_POLICY;
}
@ -2503,6 +2565,7 @@ public:
void execute(optional_yield y) override;
int get_params(optional_yield y);
const char* name() const override { return "delete_bucket_policy"; }
std::string canonical_name() const override { return fmt::format("REST.{}.BUCKETPOLICY", s->info.method); }
RGWOpType get_type() override {
return RGW_OP_DELETE_BUCKET_POLICY;
}
@ -2522,6 +2585,7 @@ public:
virtual void send_response() override = 0;
virtual int get_params(optional_yield y) = 0;
const char* name() const override { return "put_bucket_object_lock"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_LOCK", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_OBJ_LOCK; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
};
@ -2533,6 +2597,7 @@ public:
void execute(optional_yield y) override;
virtual void send_response() override = 0;
const char* name() const override {return "get_bucket_object_lock"; }
std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_LOCK", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_OBJ_LOCK; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -2551,6 +2616,7 @@ public:
virtual void send_response() override = 0;
virtual int get_params(optional_yield y) = 0;
const char* name() const override { return "put_obj_retention"; }
std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
RGWOpType get_type() override { return RGW_OP_PUT_OBJ_RETENTION; }
};
@ -2564,6 +2630,7 @@ public:
void execute(optional_yield y) override;
virtual void send_response() override = 0;
const char* name() const override {return "get_obj_retention"; }
std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_OBJ_RETENTION; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -2579,6 +2646,7 @@ public:
virtual void send_response() override = 0;
virtual int get_params(optional_yield y) = 0;
const char* name() const override { return "put_obj_legal_hold"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
RGWOpType get_type() override { return RGW_OP_PUT_OBJ_LEGAL_HOLD; }
};
@ -2592,6 +2660,7 @@ public:
void execute(optional_yield y) override;
virtual void send_response() override = 0;
const char* name() const override {return "get_obj_legal_hold"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_OBJ_LEGAL_HOLD; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -2676,6 +2745,7 @@ public:
int verify_permission(optional_yield y) override;
const char* name() const override { return "put_bucket_public_access_block";}
virtual RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_PUBLIC_ACCESS_BLOCK; }
std::string canonical_name() const override { return fmt::format("REST.{}.PUBLIC_ACCESS_BLOCK", s->info.method); }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
int get_params(optional_yield y);
void execute(optional_yield y) override;
@ -2688,6 +2758,7 @@ protected:
public:
int verify_permission(optional_yield y) override;
const char* name() const override { return "get_bucket_public_access_block";}
std::string canonical_name() const override { return fmt::format("REST.{}.PUBLIC_ACCESS_BLOCK", s->info.method); }
virtual RGWOpType get_type() override { return RGW_OP_GET_BUCKET_PUBLIC_ACCESS_BLOCK; }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
int get_params(optional_yield y);
@ -2701,6 +2772,7 @@ protected:
public:
int verify_permission(optional_yield y) override;
const char* name() const override { return "delete_bucket_public_access_block";}
std::string canonical_name() const override { return fmt::format("REST.{}.PUBLIC_ACCESS_BLOCK", s->info.method); }
virtual RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET_PUBLIC_ACCESS_BLOCK; }
virtual uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
int get_params(optional_yield y);

View File

@ -129,7 +129,10 @@ void RGWRealmReloader::reload()
cct->_conf->rgw_enable_quota_threads,
cct->_conf->rgw_run_sync_thread,
cct->_conf.get_val<bool>("rgw_dynamic_resharding"),
true, true, null_yield, // run notification thread
true,
true, // run notification thread
true, // run bucket logging thread
null_yield,
cct->_conf->rgw_cache_enabled);
}

View File

@ -129,39 +129,30 @@ public:
}
int get_params(optional_yield y) override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
};
class RGWGetObjTags_ObjStore : public RGWGetObjTags {
public:
RGWGetObjTags_ObjStore() {};
~RGWGetObjTags_ObjStore() {};
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
};
class RGWPutObjTags_ObjStore: public RGWPutObjTags {
public:
RGWPutObjTags_ObjStore() {};
~RGWPutObjTags_ObjStore() {};
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
};
class RGWGetBucketTags_ObjStore : public RGWGetBucketTags {
public:
RGWGetBucketTags_ObjStore() = default;
virtual ~RGWGetBucketTags_ObjStore() = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_TAGGING", s->info.method); }
};
class RGWPutBucketTags_ObjStore: public RGWPutBucketTags {
public:
RGWPutBucketTags_ObjStore() = default;
virtual ~RGWPutBucketTags_ObjStore() = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_TAGGING", s->info.method); }
};
class RGWGetBucketReplication_ObjStore : public RGWGetBucketReplication {
@ -186,56 +177,42 @@ class RGWListBuckets_ObjStore : public RGWListBuckets {
public:
RGWListBuckets_ObjStore() {}
~RGWListBuckets_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKETS", s->info.method); }
};
class RGWGetUsage_ObjStore : public RGWGetUsage {
public:
RGWGetUsage_ObjStore() {}
~RGWGetUsage_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.USER_USAGE", s->info.method); }
};
class RGWListBucket_ObjStore : public RGWListBucket {
public:
RGWListBucket_ObjStore() {}
~RGWListBucket_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
};
class RGWStatAccount_ObjStore : public RGWStatAccount {
public:
RGWStatAccount_ObjStore() {}
~RGWStatAccount_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.ACCOUNT_STATUS", s->info.method); }
};
class RGWStatBucket_ObjStore : public RGWStatBucket {
public:
RGWStatBucket_ObjStore() {}
~RGWStatBucket_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_STATUS", s->info.method); }
};
class RGWCreateBucket_ObjStore : public RGWCreateBucket {
public:
RGWCreateBucket_ObjStore() {}
~RGWCreateBucket_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
};
class RGWDeleteBucket_ObjStore : public RGWDeleteBucket {
public:
RGWDeleteBucket_ObjStore() {}
~RGWDeleteBucket_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET", s->info.method); }
};
class RGWPutObj_ObjStore : public RGWPutObj
@ -247,11 +224,6 @@ public:
int verify_params() override;
int get_params(optional_yield y) override;
int get_data(bufferlist& bl) override;
virtual std::string canonical_name() const override {
const bool multipart = !multipart_upload_id.empty();
return fmt::format("REST.{}.{}", s->info.method, multipart ? "PART" : "OBJECT");
}
};
class RGWPostObj_ObjStore : public RGWPostObj
@ -322,7 +294,6 @@ public:
~RGWPostObj_ObjStore() override {}
int verify_params() override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
};
@ -331,8 +302,6 @@ class RGWPutMetadataAccount_ObjStore : public RGWPutMetadataAccount
public:
RGWPutMetadataAccount_ObjStore() {}
~RGWPutMetadataAccount_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.ACCOUNT_METADATA", s->info.method); }
};
class RGWPutMetadataBucket_ObjStore : public RGWPutMetadataBucket
@ -340,8 +309,6 @@ class RGWPutMetadataBucket_ObjStore : public RGWPutMetadataBucket
public:
RGWPutMetadataBucket_ObjStore() {}
~RGWPutMetadataBucket_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_METADATA", s->info.method); }
};
class RGWPutMetadataObject_ObjStore : public RGWPutMetadataObject
@ -349,24 +316,18 @@ class RGWPutMetadataObject_ObjStore : public RGWPutMetadataObject
public:
RGWPutMetadataObject_ObjStore() {}
~RGWPutMetadataObject_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_METADATA", s->info.method); }
};
class RGWRestoreObj_ObjStore : public RGWRestoreObj {
public:
RGWRestoreObj_ObjStore() {}
~RGWRestoreObj_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
};
class RGWDeleteObj_ObjStore : public RGWDeleteObj {
public:
RGWDeleteObj_ObjStore() {}
~RGWDeleteObj_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
};
class RGWGetCrossDomainPolicy_ObjStore : public RGWGetCrossDomainPolicy {
@ -385,25 +346,19 @@ class RGWCopyObj_ObjStore : public RGWCopyObj {
public:
RGWCopyObj_ObjStore() {}
~RGWCopyObj_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT", s->info.method); }
};
class RGWGetACLs_ObjStore : public RGWGetACLs {
public:
RGWGetACLs_ObjStore() {}
~RGWGetACLs_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.ACL", s->info.method); }
};
class RGWPutACLs_ObjStore : public RGWPutACLs {
public:
RGWPutACLs_ObjStore() {}
~RGWPutACLs_ObjStore() override {}
int get_params(optional_yield y) override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.ACL", s->info.method); }
};
class RGWGetObjAttrs_ObjStore : public RGWGetObjAttrs {
@ -421,8 +376,6 @@ class RGWGetLC_ObjStore : public RGWGetLC {
public:
RGWGetLC_ObjStore() {}
~RGWGetLC_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
};
class RGWPutLC_ObjStore : public RGWPutLC {
@ -431,47 +384,36 @@ public:
~RGWPutLC_ObjStore() override {}
int get_params(optional_yield y) override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
};
class RGWDeleteLC_ObjStore : public RGWDeleteLC {
public:
RGWDeleteLC_ObjStore() {}
~RGWDeleteLC_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.LIFECYCLE", s->info.method); }
};
class RGWGetCORS_ObjStore : public RGWGetCORS {
public:
RGWGetCORS_ObjStore() {}
~RGWGetCORS_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
};
class RGWPutCORS_ObjStore : public RGWPutCORS {
public:
RGWPutCORS_ObjStore() {}
~RGWPutCORS_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
};
class RGWDeleteCORS_ObjStore : public RGWDeleteCORS {
public:
RGWDeleteCORS_ObjStore() {}
~RGWDeleteCORS_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
};
class RGWOptionsCORS_ObjStore : public RGWOptionsCORS {
public:
RGWOptionsCORS_ObjStore() {}
~RGWOptionsCORS_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.CORS", s->info.method); }
};
class RGWGetBucketEncryption_ObjStore : public RGWGetBucketEncryption {
@ -496,16 +438,12 @@ class RGWInitMultipart_ObjStore : public RGWInitMultipart {
public:
RGWInitMultipart_ObjStore() {}
~RGWInitMultipart_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.UPLOADS", s->info.method); }
};
class RGWCompleteMultipart_ObjStore : public RGWCompleteMultipart {
public:
RGWCompleteMultipart_ObjStore() {}
~RGWCompleteMultipart_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
int get_params(optional_yield y) override;
};
@ -513,16 +451,12 @@ class RGWAbortMultipart_ObjStore : public RGWAbortMultipart {
public:
RGWAbortMultipart_ObjStore() {}
~RGWAbortMultipart_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
};
class RGWListMultipart_ObjStore : public RGWListMultipart {
public:
RGWListMultipart_ObjStore() {}
~RGWListMultipart_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.UPLOAD", s->info.method); }
int get_params(optional_yield y) override;
};
@ -530,8 +464,6 @@ class RGWListBucketMultiparts_ObjStore : public RGWListBucketMultiparts {
public:
RGWListBucketMultiparts_ObjStore() {}
~RGWListBucketMultiparts_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.UPLOADS", s->info.method); }
int get_params(optional_yield y) override;
};
@ -539,16 +471,12 @@ class RGWBulkDelete_ObjStore : public RGWBulkDelete {
public:
RGWBulkDelete_ObjStore() {}
~RGWBulkDelete_ObjStore() override {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BULK_DELETE", s->info.method); }
};
class RGWBulkUploadOp_ObjStore : public RGWBulkUploadOp {
public:
RGWBulkUploadOp_ObjStore() = default;
~RGWBulkUploadOp_ObjStore() = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BULK_UPLOAD", s->info.method); }
};
class RGWDeleteMultiObj_ObjStore : public RGWDeleteMultiObj {
@ -557,7 +485,6 @@ public:
~RGWDeleteMultiObj_ObjStore() override {}
int get_params(optional_yield y) override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.DELETE_MULTI_OBJECT", s->info.method); }
};
class RGWInfo_ObjStore : public RGWInfo {
@ -583,14 +510,12 @@ class RGWPutObjRetention_ObjStore : public RGWPutObjRetention {
public:
RGWPutObjRetention_ObjStore() = default;
~RGWPutObjRetention_ObjStore() override = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
};
class RGWGetObjRetention_ObjStore : public RGWGetObjRetention {
public:
RGWGetObjRetention_ObjStore() = default;
~RGWGetObjRetention_ObjStore() = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
};
class RGWPutObjLegalHold_ObjStore : public RGWPutObjLegalHold {
@ -598,13 +523,11 @@ public:
RGWPutObjLegalHold_ObjStore() = default;
~RGWPutObjLegalHold_ObjStore() override = default;
int get_params(optional_yield y) override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
};
class RGWGetObjLegalHold_ObjStore : public RGWGetObjLegalHold {
public:
RGWGetObjLegalHold_ObjStore() = default;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
~RGWGetObjLegalHold_ObjStore() = default;
};

View File

@ -111,6 +111,7 @@ public:
}
void send_response() override {
set_req_state_err(s, op_ret);
dump_errno(s);
if (mtime) {
dump_last_modified(s, *mtime);
@ -123,7 +124,9 @@ public:
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
}
const char* name() const override { return "get_bucket_logging"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LOGGING", s->info.method); }
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_LOGGING; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
};
@ -135,6 +138,7 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
// and usd in execute()
rgw::bucketlogging::configuration configuration;
std::unique_ptr<rgw::sal::Bucket> target_bucket;
std::string old_obj; // used when conf change triggers a rollover
int init_processing(optional_yield y) override {
if (const auto ret = verify_bucket_logging_params(this, s); ret < 0) {
@ -177,13 +181,13 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
rgw_bucket target_bucket_id;
if (const auto ret = rgw::bucketlogging::get_bucket_id(configuration.target_bucket, s->bucket_tenant, target_bucket_id); ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to parse target bucket '" << configuration.target_bucket << "', ret = " << ret << dendl;
ldpp_dout(this, 1) << "ERROR: failed to parse logging bucket '" << configuration.target_bucket << "', ret = " << ret << dendl;
return ret;
}
if (const auto ret = driver->load_bucket(this, target_bucket_id,
&target_bucket, y); ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to get target bucket '" << target_bucket_id << "', ret = " << ret << dendl;
ldpp_dout(this, 1) << "ERROR: failed to get logging bucket '" << target_bucket_id << "', ret = " << ret << dendl;
return ret;
}
@ -215,6 +219,7 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
}
const char* name() const override { return "put_bucket_logging"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LOGGING", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_LOGGING; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
@ -232,7 +237,7 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
}
if (!configuration.enabled) {
op_ret = rgw::bucketlogging::source_bucket_cleanup(this, driver, src_bucket.get(), true, y);
op_ret = rgw::bucketlogging::source_bucket_cleanup(this, driver, src_bucket.get(), true, y, &old_obj);
return;
}
@ -240,14 +245,14 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
const auto& target_bucket_id = target_bucket->get_key();
if (target_bucket_id == src_bucket_id) {
// target bucket must be different from source bucket (cannot change later on)
ldpp_dout(this, 1) << "ERROR: target bucket '" << target_bucket_id << "' must be different from source bucket" << dendl;
ldpp_dout(this, 1) << "ERROR: logging bucket '" << target_bucket_id << "' must be different from source bucket" << dendl;
op_ret = -EINVAL;
return;
}
const auto& target_info = target_bucket->get_info();
if (target_info.zonegroup != src_bucket->get_info().zonegroup) {
// target bucket must be in the same zonegroup as source bucket (cannot change later on)
ldpp_dout(this, 1) << "ERROR: target bucket '" << target_bucket_id << "' zonegroup '" <<
ldpp_dout(this, 1) << "ERROR: logging bucket '" << target_bucket_id << "' zonegroup '" <<
target_info.zonegroup << "' is different from the source bucket '" << src_bucket_id <<
"' zonegroup '" << src_bucket->get_info().zonegroup << "'" << dendl;
op_ret = -EINVAL;
@ -299,30 +304,51 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
ldpp_dout(this, 20) << "INFO: new logging configuration added to bucket '" << src_bucket_id << "'. configuration: " <<
configuration.to_json_str() << dendl;
if (const auto ret = rgw::bucketlogging::update_bucket_logging_sources(this, target_bucket, src_bucket_id, true, y); ret < 0) {
ldpp_dout(this, 1) << "WARNING: failed to add source bucket '" << src_bucket_id << "' to logging sources of target bucket '" <<
ldpp_dout(this, 1) << "WARNING: failed to add source bucket '" << src_bucket_id << "' to logging sources of logging bucket '" <<
target_bucket_id << "', ret = " << ret << dendl;
}
} else if (*old_conf != configuration) {
// conf changed - do cleanup
if (const auto ret = commit_logging_object(*old_conf, target_bucket, this, y, nullptr); ret < 0) {
ldpp_dout(this, 1) << "WARNING: could not commit pending logging object when updating logging configuration of bucket '" <<
src_bucket->get_key() << "', ret = " << ret << dendl;
RGWObjVersionTracker objv_tracker;
std::string obj_name;
if (int ret = target_bucket->get_logging_object_name(obj_name, old_conf->target_prefix, y, this, nullptr); ret < 0 && ret != -ENOENT) {
ldpp_dout(this, 1) << "ERROR: failed to get name of logging object of logging bucket '" <<
target_bucket_id << "' and prefix '" << configuration.target_prefix << "', ret = " << ret << dendl;
op_ret = ret;
return;
}
const auto region = driver->get_zone()->get_zonegroup().get_api_name();
if (const auto ret = rollover_logging_object(*old_conf,
target_bucket,
obj_name,
this,
region,
src_bucket,
y,
false, // rollover should happen even if commit failed
&objv_tracker,
false,
&old_obj); ret < 0) {
ldpp_dout(this, 1) << "WARNING: failed to flush pending logging object '" << obj_name << "'"
<< " to target bucket '" << target_bucket_id << "'. "
<< "' when updating logging configuration of bucket '" << src_bucket->get_key() << ". error: " << ret << dendl;
} else {
ldpp_dout(this, 20) << "INFO: committed pending logging object when updating logging configuration of bucket '" <<
src_bucket->get_key() << "'" << dendl;
ldpp_dout(this, 20) << "INFO: flushed pending logging object '" << old_obj
<< "' to target bucket '" << target_bucket_id << "' when updating logging configuration of bucket '"
<< src_bucket->get_key() << "'" << dendl;
}
if (old_conf->target_bucket != configuration.target_bucket) {
rgw_bucket old_target_bucket_id;
if (const auto ret = rgw::bucketlogging::get_bucket_id(old_conf->target_bucket, s->bucket_tenant, old_target_bucket_id); ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to parse target bucket '" << old_conf->target_bucket << "', ret = " << ret << dendl;
ldpp_dout(this, 1) << "ERROR: failed to parse logging bucket '" << old_conf->target_bucket << "', ret = " << ret << dendl;
return;
}
if (const auto ret = rgw::bucketlogging::update_bucket_logging_sources(this, driver, old_target_bucket_id, src_bucket_id, false, y); ret < 0) {
ldpp_dout(this, 1) << "WARNING: failed to remove source bucket '" << src_bucket_id << "' from logging sources of original target bucket '" <<
ldpp_dout(this, 1) << "WARNING: failed to remove source bucket '" << src_bucket_id << "' from logging sources of original logging bucket '" <<
old_target_bucket_id << "', ret = " << ret << dendl;
}
if (const auto ret = rgw::bucketlogging::update_bucket_logging_sources(this, target_bucket, src_bucket_id, true, y); ret < 0) {
ldpp_dout(this, 1) << "WARNING: failed to add source bucket '" << src_bucket_id << "' to logging sources of target bucket '" <<
ldpp_dout(this, 1) << "WARNING: failed to add source bucket '" << src_bucket_id << "' to logging sources of logging bucket '" <<
target_bucket_id << "', ret = " << ret << dendl;
}
}
@ -332,6 +358,19 @@ class RGWPutBucketLoggingOp : public RGWDefaultResponseOp {
ldpp_dout(this, 20) << "INFO: logging configuration of bucket '" << src_bucket_id << "' did not change" << dendl;
}
}
void send_response() override {
set_req_state_err(s, op_ret);
dump_errno(s);
end_header(s, this, to_mime_type(s->format));
if (!old_obj.empty()) {
dump_start(s);
s->formatter->open_object_section_in_ns("PutBucketLoggingOutput", XMLNS_AWS_S3);
s->formatter->dump_string("FlushedLoggingObject", old_obj);
s->formatter->close_section();
rgw_flush_formatter_and_reset(s, s->formatter);
}
}
};
// Post /<bucket name>/?logging
@ -373,38 +412,44 @@ class RGWPostBucketLoggingOp : public RGWDefaultResponseOp {
}
const char* name() const override { return "post_bucket_logging"; }
std::string canonical_name() const override { return fmt::format("REST.{}.LOGGING", s->info.method); }
RGWOpType get_type() override { return RGW_OP_POST_BUCKET_LOGGING; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
void execute(optional_yield y) override {
const auto& target_bucket_id = target_bucket->get_key();
// make sure that the logging source attribute is up-to-date
if (const auto ret = rgw::bucketlogging::update_bucket_logging_sources(this, target_bucket, source_bucket->get_key(), true, y); ret < 0) {
ldpp_dout(this, 5) << "WARNING: failed to update logging sources attribute '" << RGW_ATTR_BUCKET_LOGGING_SOURCES
<< "' in logging target '" << target_bucket_id << "'. error: " << ret << dendl;
}
std::string obj_name;
RGWObjVersionTracker objv_tracker;
op_ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, null_yield, this, &objv_tracker);
if (op_ret < 0) {
ldpp_dout(this, 1) << "ERROR: failed to get pending logging object name from target bucket '" << target_bucket_id << "'" << dendl;
op_ret = target_bucket->get_logging_object_name(obj_name, configuration.target_prefix, y, this, &objv_tracker);
if (op_ret < 0 && op_ret != -ENOENT) {
ldpp_dout(this, 1) << "ERROR: failed to get pending logging object name from logging bucket '" << target_bucket_id <<
"'. error: " << op_ret << dendl;
return;
}
if (op_ret == -ENOENT) {
// no pending object - nothing to flush
ldpp_dout(this, 5) << "INFO: no pending logging object in logging bucket '" << target_bucket_id << "'. new object should be created" << dendl;
}
const auto region = driver->get_zone()->get_zonegroup().get_api_name();
op_ret = rgw::bucketlogging::rollover_logging_object(configuration, target_bucket, obj_name, this, region, source_bucket, null_yield, true, &objv_tracker, &old_obj);
op_ret = rgw::bucketlogging::rollover_logging_object(configuration, target_bucket, obj_name, this, region, source_bucket, y, true, &objv_tracker, false, &old_obj);
if (op_ret < 0) {
if (op_ret == -ENOENT) {
ldpp_dout(this, 5) << "WARNING: no pending logging object '" << obj_name << "'. nothing to flush"
<< " to target bucket '" << target_bucket_id << "'. "
<< " last committed object is '" << old_obj << "'" << dendl;
op_ret = 0;
} else {
ldpp_dout(this, 1) << "ERROR: failed flush pending logging object '" << obj_name << "'"
<< " to target bucket '" << target_bucket_id << "'. "
<< " last committed object is '" << old_obj << "'" << dendl;
}
ldpp_dout(this, 1) << "ERROR: failed to flush pending logging object '" << obj_name << "'"
<< " to logging bucket '" << target_bucket_id << "'. "
<< " last committed object is '" << old_obj <<
"'. error: " << op_ret << dendl;
return;
}
ldpp_dout(this, 20) << "INFO: flushed pending logging object '" << old_obj
<< "' to target bucket '" << target_bucket_id << "'" << dendl;
<< "' to logging bucket '" << target_bucket_id << "'" << dendl;
}
void send_response() override {
set_req_state_err(s, op_ret);
dump_errno(s);
end_header(s, this, to_mime_type(s->format));
dump_start(s);

View File

@ -1189,6 +1189,7 @@ public:
}
const char* name() const override { return "pubsub_notification_create_s3"; }
std::string canonical_name() const override { return fmt::format("REST.{}.NOTIFICATION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUBSUB_NOTIF_CREATE; }
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
@ -1444,6 +1445,7 @@ class RGWPSDeleteNotifOp : public RGWDefaultResponseOp {
}
const char* name() const override { return "pubsub_notification_delete_s3"; }
std::string canonical_name() const override { return fmt::format("REST.{}.NOTIFICATION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUBSUB_NOTIF_DELETE; }
uint32_t op_mask() override { return RGW_OP_TYPE_DELETE; }
@ -1548,6 +1550,7 @@ public:
}
const char* name() const override { return "pubsub_notifications_get_s3"; }
std::string canonical_name() const override { return fmt::format("REST.{}.NOTIFICATION", s->info.method); }
RGWOpType get_type() override { return RGW_OP_PUBSUB_NOTIF_LIST; }
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }

View File

@ -83,7 +83,6 @@ class RGWDeleteObjTags_ObjStore_S3 : public RGWDeleteObjTags
public:
~RGWDeleteObjTags_ObjStore_S3() override {}
void send_response() override;
virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
};
class RGWGetBucketTags_ObjStore_S3 : public RGWGetBucketTags_ObjStore
@ -215,7 +214,6 @@ public:
~RGWGetBucketWebsite_ObjStore_S3() override {}
void send_response() override;
virtual std::string canonical_name() const override { return fmt::format("WEBSITE.{}.BUCKET_WEBSITE", s->info.method); }
};
class RGWSetBucketWebsite_ObjStore_S3 : public RGWSetBucketWebsite {
@ -225,7 +223,6 @@ public:
int get_params(optional_yield y) override;
void send_response() override;
virtual std::string canonical_name() const override { return fmt::format("WEBSITE.{}.BUCKET_WEBSITE", s->info.method); }
};
class RGWDeleteBucketWebsite_ObjStore_S3 : public RGWDeleteBucketWebsite {
@ -234,7 +231,6 @@ public:
~RGWDeleteBucketWebsite_ObjStore_S3() override {}
void send_response() override;
virtual std::string canonical_name() const override { return fmt::format("WEBSITE.{}.BUCKET_WEBSITE", s->info.method); }
};
class RGWStatBucket_ObjStore_S3 : public RGWStatBucket_ObjStore {
@ -604,7 +600,6 @@ class RGWConfigBucketMetaSearch_ObjStore_S3 : public RGWConfigBucketMetaSearch {
public:
RGWConfigBucketMetaSearch_ObjStore_S3() {}
~RGWConfigBucketMetaSearch_ObjStore_S3() {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_MDSEARCH", s->info.method); }
int get_params(optional_yield y) override;
void send_response() override;
@ -622,7 +617,6 @@ class RGWDelBucketMetaSearch_ObjStore_S3 : public RGWDelBucketMetaSearch {
public:
RGWDelBucketMetaSearch_ObjStore_S3() {}
~RGWDelBucketMetaSearch_ObjStore_S3() {}
virtual std::string canonical_name() const override { return fmt::format("REST.{}.BUCKET_MDSEARCH", s->info.method); }
void send_response() override;
};

View File

@ -97,4 +97,5 @@ public:
return RGWGetObj_ObjStore_S3::get_params(y);
}
}
std::string canonical_name() const override { return fmt::format("WEBSITE.{}.OBJECT", s->info.method); }
};

View File

@ -95,7 +95,8 @@ rgw::sal::Driver* DriverManager::init_storage_provider(const DoutPrefixProvider*
bool quota_threads,
bool run_sync_thread,
bool run_reshard_thread,
bool run_notification_thread,
bool run_notification_thread,
bool run_bucket_logging_thread,
bool use_cache,
bool use_gc,
bool background_tasks,
@ -117,6 +118,7 @@ rgw::sal::Driver* DriverManager::init_storage_provider(const DoutPrefixProvider*
.set_run_sync_thread(run_sync_thread)
.set_run_reshard_thread(run_reshard_thread)
.set_run_notification_thread(run_notification_thread)
.set_run_bucket_logging_thread(run_bucket_logging_thread)
.init_begin(cct, dpp, background_tasks, site_config) < 0) {
delete driver;
return nullptr;
@ -149,6 +151,7 @@ rgw::sal::Driver* DriverManager::init_storage_provider(const DoutPrefixProvider*
.set_run_sync_thread(run_sync_thread)
.set_run_reshard_thread(run_reshard_thread)
.set_run_notification_thread(run_notification_thread)
.set_run_bucket_logging_thread(run_bucket_logging_thread)
.init_begin(cct, dpp, background_tasks, site_config) < 0) {
delete driver;
return nullptr;

View File

@ -1053,12 +1053,15 @@ class Bucket {
RGWObjVersionTracker* objv_tracker) = 0;
/** Move the pending bucket logging object into the bucket
if "last_committed" is not null, it will be set to the name of the last committed object
if async is true, write the entry to the commit lists to be processed by the BucketLoggingManager
* */
virtual int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed) = 0;
virtual int commit_logging_object(const std::string& obj_name, optional_yield y,
const DoutPrefixProvider *dpp, const std::string& prefix,
std::string* last_committed, bool async) = 0;
//** Remove the pending bucket logging object */
virtual int remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) = 0;
virtual int remove_logging_object(const std::string& obj_name, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp) = 0;
/** Write a record to the pending bucket logging object */
virtual int write_logging_object(const std::string& obj_name, const std::string& record, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) = 0;
virtual int write_logging_object(const std::string& obj_name, const std::string& record, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) = 0;
/* dang - This is temporary, until the API is completed */
virtual rgw_bucket& get_key() = 0;
@ -1948,6 +1951,7 @@ public:
bool run_sync_thread,
bool run_reshard_thread,
bool run_notification_thread,
bool run_bucket_logging_thread,
bool background_tasks,
optional_yield y,
bool use_cache = true,
@ -1961,6 +1965,7 @@ public:
run_sync_thread,
run_reshard_thread,
run_notification_thread,
run_bucket_logging_thread,
use_cache, use_gc,
background_tasks, y);
return driver;
@ -1988,6 +1993,7 @@ public:
bool run_sync_thread,
bool run_reshard_thread,
bool run_notification_thread,
bool run_bucket_logging_thread,
bool use_metadata_cache,
bool use_gc, bool background_tasks,
optional_yield y);

View File

@ -697,14 +697,14 @@ public:
RGWObjVersionTracker* objv_tracker) override {
return next->remove_logging_object_name(prefix, y, dpp, objv_tracker);
}
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed) override {
return next->commit_logging_object(obj_name, y, dpp, prefix, last_committed);
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed, bool async) override {
return next->commit_logging_object(obj_name, y, dpp, prefix, last_committed, async);
}
int remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) override {
return next->remove_logging_object(obj_name, y, dpp);
int remove_logging_object(const std::string& obj_name, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp) override {
return next->remove_logging_object(obj_name, prefix, y, dpp);
}
int write_logging_object(const std::string& obj_name, const std::string& record, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override {
return next->write_logging_object(obj_name, record, y, dpp, async_completion);
int write_logging_object(const std::string& obj_name, const std::string& record, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override {
return next->write_logging_object(obj_name, record, prefix, y, dpp, async_completion);
}
virtual rgw_bucket& get_key() override { return next->get_key(); }

View File

@ -266,9 +266,9 @@ class StoreBucket : public Bucket {
optional_yield y,
const DoutPrefixProvider *dpp,
RGWObjVersionTracker* objv_tracker) override { return 0; }
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed) override { return 0; }
int remove_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp) override { return 0; }
int write_logging_object(const std::string& obj_name, const std::string& record, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override {
int commit_logging_object(const std::string& obj_name, optional_yield y, const DoutPrefixProvider *dpp, const std::string& prefix, std::string* last_committed, bool async) override { return 0; }
int remove_logging_object(const std::string& obj_name, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp) override { return 0; }
int write_logging_object(const std::string& obj_name, const std::string& record, const std::string& prefix, optional_yield y, const DoutPrefixProvider *dpp, bool async_completion) override {
return 0;
}

View File

@ -301,6 +301,7 @@ void RGWZoneParams::decode_json(JSONObj *obj)
JSONDecoder::decode_json("topics_pool", topics_pool, obj);
JSONDecoder::decode_json("account_pool", account_pool, obj);
JSONDecoder::decode_json("group_pool", group_pool, obj);
JSONDecoder::decode_json("bucket_logging_pool", bucket_logging_pool, obj);
JSONDecoder::decode_json("system_key", system_key, obj);
JSONDecoder::decode_json("placement_pools", placement_pools, obj);
JSONDecoder::decode_json("tier_config", tier_config, obj);
@ -330,6 +331,7 @@ void RGWZoneParams::dump(Formatter *f) const
encode_json("topics_pool", topics_pool, f);
encode_json("account_pool", account_pool, f);
encode_json("group_pool", group_pool, f);
encode_json("bucket_logging_pool", bucket_logging_pool, f);
encode_json_plain("system_key", system_key, f);
encode_json("placement_pools", placement_pools, f);
encode_json("tier_config", tier_config, f);
@ -479,6 +481,7 @@ void add_zone_pools(const RGWZoneParams& info,
pools.insert(info.dedup_pool);
pools.insert(info.gc_pool);
pools.insert(info.log_pool);
pools.insert(info.bucket_logging_pool);
pools.insert(info.intent_log_pool);
pools.insert(info.usage_log_pool);
pools.insert(info.user_keys_pool);
@ -1295,6 +1298,7 @@ int init_zone_pool_names(const DoutPrefixProvider *dpp, optional_yield y,
info.otp_pool = fix_zone_pool_dup(pools, info.name, ".rgw.otp", info.otp_pool);
info.oidc_pool = fix_zone_pool_dup(pools, info.name, ".rgw.meta:oidc", info.oidc_pool);
info.notif_pool = fix_zone_pool_dup(pools, info.name, ".rgw.log:notif", info.notif_pool);
info.bucket_logging_pool = fix_zone_pool_dup(pools, info.name, ".rgw.log:logging", info.bucket_logging_pool);
info.topics_pool =
fix_zone_pool_dup(pools, info.name, ".rgw.meta:topics", info.topics_pool);
info.account_pool = fix_zone_pool_dup(pools, info.name, ".rgw.meta:accounts", info.account_pool);

View File

@ -52,6 +52,7 @@
bucket radoslist list rados objects backing bucket's objects
bucket logging flush flush pending log records object of source bucket to the log bucket
bucket logging info get info on bucket logging configuration on source bucket or list of sources in log bucket
bucket logging list list the log objects pending commit for the source bucket
bi get retrieve bucket index object entries
bi put store bucket index object entries
bi list list raw bucket index entries

View File

@ -351,7 +351,7 @@ int main(int argc, const char **argv)
false,
false,
false,
true, true, null_yield,
true, true, true, null_yield,
false));
if (!store) {
std::cerr << "couldn't init storage provider" << std::endl;