generic_server: Allow sharing reloadability of certificates across shards

Adds an optional callback to "listen", returning the shard local object
instance. If provided, instead of creating a "full" reloadable cerificate
object, only do so on shard 0, and use callback to reload other shards
"manually".
This commit is contained in:
Calle Wilund
2025-01-21 12:19:32 +00:00
parent fb4c7dc3d8
commit c59c87c233
2 changed files with 38 additions and 13 deletions

View File

@@ -13,6 +13,7 @@
#include <seastar/core/when_all.hh> #include <seastar/core/when_all.hh>
#include <seastar/coroutine/parallel_for_each.hh> #include <seastar/coroutine/parallel_for_each.hh>
#include <seastar/core/reactor.hh> #include <seastar/core/reactor.hh>
#include <seastar/core/smp.hh>
namespace generic_server { namespace generic_server {
@@ -167,16 +168,34 @@ future<> server::shutdown() {
} }
future<> future<>
server::listen(socket_address addr, std::shared_ptr<seastar::tls::credentials_builder> builder, bool is_shard_aware, bool keepalive, std::optional<file_permissions> unix_domain_socket_permissions) { server::listen(socket_address addr, std::shared_ptr<seastar::tls::credentials_builder> builder, bool is_shard_aware, bool keepalive, std::optional<file_permissions> unix_domain_socket_permissions, std::function<server&()> get_shard_instance) {
shared_ptr<seastar::tls::server_credentials> creds = nullptr; // Note: We are making the assumption that if builder is provided it will be the same for each
if (builder) { // invokation, regardless of address etc. In general, only CQL server will call this multiple times,
creds = co_await builder->build_reloadable_server_credentials([this](const std::unordered_set<sstring>& files, std::exception_ptr ep) { // and if TLS, it will use the same cert set.
if (ep) { // Could hold certs in a map<addr, certs> and ensure separation, but then we will for all
_logger.warn("Exception loading {}: {}", files, ep); // current uses of this class create duplicate reloadable certs for shard 0, which is
} else { // kind of what we wanted to avoid in the first place...
_logger.info("Reloaded {}", files); if (builder && !_credentials) {
} if (!get_shard_instance || this_shard_id() == 0) {
}); _credentials = co_await builder->build_reloadable_server_credentials([this, get_shard_instance = std::move(get_shard_instance)](const tls::credentials_builder& b, const std::unordered_set<sstring>& files, std::exception_ptr ep) -> future<> {
if (ep) {
_logger.warn("Exception loading {}: {}", files, ep);
} else {
if (get_shard_instance) {
co_await smp::invoke_on_others([&]() {
auto& s = get_shard_instance();
if (s._credentials) {
b.rebuild(*s._credentials);
}
});
}
_logger.info("Reloaded {}", files);
}
});
} else {
_credentials = builder->build_server_credentials();
}
} }
listen_options lo; listen_options lo;
lo.reuse_address = true; lo.reuse_address = true;
@@ -186,8 +205,8 @@ server::listen(socket_address addr, std::shared_ptr<seastar::tls::credentials_bu
} }
server_socket ss; server_socket ss;
try { try {
ss = creds ss = builder
? seastar::tls::listen(std::move(creds), addr, lo) ? seastar::tls::listen(_credentials, addr, lo)
: seastar::listen(addr, lo); : seastar::listen(addr, lo);
} catch (...) { } catch (...) {
throw std::runtime_error(format("{} error while listening on {} -> {}", _server_name, addr, std::current_exception())); throw std::runtime_error(format("{} error while listening on {} -> {}", _server_name, addr, std::current_exception()));

View File

@@ -104,6 +104,7 @@ protected:
}; };
std::list<gentle_iterator> _gentle_iterators; std::list<gentle_iterator> _gentle_iterators;
std::vector<server_socket> _listeners; std::vector<server_socket> _listeners;
shared_ptr<seastar::tls::server_credentials> _credentials;
public: public:
server(const sstring& server_name, logging::logger& logger); server(const sstring& server_name, logging::logger& logger);
@@ -119,7 +120,12 @@ public:
future<> shutdown(); future<> shutdown();
future<> stop(); future<> stop();
future<> listen(socket_address addr, std::shared_ptr<seastar::tls::credentials_builder> creds, bool is_shard_aware, bool keepalive, std::optional<file_permissions> unix_domain_socket_permissions); future<> listen(socket_address addr,
std::shared_ptr<seastar::tls::credentials_builder> creds,
bool is_shard_aware, bool keepalive,
std::optional<file_permissions> unix_domain_socket_permissions,
std::function<server&()> get_shard_instance = {}
);
future<> do_accepts(int which, bool keepalive, socket_address server_addr); future<> do_accepts(int which, bool keepalive, socket_address server_addr);