diff options
author | Juan Miguel Olmo Martínez <jolmomar@redhat.com> | 2024-10-25 14:57:44 +0200 |
---|---|---|
committer | Juan Miguel Olmo Martínez <jolmomar@redhat.com> | 2024-11-15 14:35:56 +0100 |
commit | 6e0324f26b25eba333feb4684c05b26391f2a24a (patch) | |
tree | 6bdadaeb9a76b9fe71d5e11afe2d4de1640fd3f4 /src | |
parent | Merge pull request #60433 from indirasawant/doc_fix_1 (diff) | |
download | ceph-6e0324f26b25eba333feb4684c05b26391f2a24a.tar.xz ceph-6e0324f26b25eba333feb4684c05b26391f2a24a.zip |
exporter: SIGTERM/SIGINT/SIGHUP management
Ceph exporter manages SIGINT, SIGTERM and SIGHUP signals
Fixes: https://tracker.ceph.com/issues/68721
Signed-off-by: Juan Miguel Olmo Martínez <jolmomar@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/exporter/DaemonMetricCollector.cc | 31 | ||||
-rw-r--r-- | src/exporter/DaemonMetricCollector.h | 11 | ||||
-rw-r--r-- | src/exporter/ceph_exporter.cc | 46 | ||||
-rw-r--r-- | src/exporter/web_server.cc | 35 | ||||
-rw-r--r-- | src/exporter/web_server.h | 1 |
5 files changed, 97 insertions, 27 deletions
diff --git a/src/exporter/DaemonMetricCollector.cc b/src/exporter/DaemonMetricCollector.cc index 4b8a8131bcf..d27b3ac43c5 100644 --- a/src/exporter/DaemonMetricCollector.cc +++ b/src/exporter/DaemonMetricCollector.cc @@ -29,9 +29,16 @@ using json_object = boost::json::object; using json_value = boost::json::value; using json_array = boost::json::array; -void DaemonMetricCollector::request_loop(boost::asio::steady_timer &timer) { - timer.async_wait([&](const boost::system::error_code &e) { - std::cerr << e << std::endl; +void DaemonMetricCollector::request_loop() { + timer.async_wait([this](const boost::system::error_code &e) { + if (shutdown_flag) { + dout(1) << "Metric collector request loop cancelled" << dendl; + return; + } + + if (e) return; // Exit on error or cancellation + + dout(10) << "Getting metrics loop..." << dendl; update_sockets(); bool sort_metrics = g_conf().get_val<bool>("exporter_sort_metrics"); @@ -42,19 +49,24 @@ void DaemonMetricCollector::request_loop(boost::asio::steady_timer &timer) { auto stats_period = g_conf().get_val<int64_t>("exporter_stats_period"); // time to wait before sending requests again timer.expires_from_now(std::chrono::seconds(stats_period)); - request_loop(timer); + request_loop(); }); } void DaemonMetricCollector::main() { - // time to wait before sending requests again - - boost::asio::io_context io; - boost::asio::steady_timer timer{io, std::chrono::seconds(0)}; - request_loop(timer); + shutdown_flag = false; + timer.expires_from_now(std::chrono::seconds(0)); + request_loop(); io.run(); } +void DaemonMetricCollector::shutdown(){ + shutdown_flag = true; + timer.cancel(); // Explicitly cancel the timer + dout(1) << "Collector shutdown initiated, timer canceled" << dendl; + io.stop(); +} + std::string DaemonMetricCollector::get_metrics() { const std::lock_guard<std::mutex> lock(metrics_mutex); return metrics; @@ -499,3 +511,4 @@ DaemonMetricCollector &collector_instance() { static DaemonMetricCollector instance; return instance; } + diff --git a/src/exporter/DaemonMetricCollector.h b/src/exporter/DaemonMetricCollector.h index 3302e95df91..5831a0fa3b0 100644 --- a/src/exporter/DaemonMetricCollector.h +++ b/src/exporter/DaemonMetricCollector.h @@ -1,17 +1,20 @@ #pragma once #include "common/admin_socket_client.h" +#include <atomic> #include <map> #include <string> #include <vector> #include <boost/asio/steady_timer.hpp> +#include <boost/thread.hpp> #include <boost/json/object.hpp> #include <filesystem> #include <map> #include <string> #include <vector> + struct pstat { unsigned long utime; unsigned long stime; @@ -43,11 +46,16 @@ public: std::string metrics; std::pair<labels_t, std::string> add_fixed_name_metrics(std::string metric_name); void update_sockets(); + void shutdown(); private: std::mutex metrics_mutex; std::unique_ptr<MetricsBuilder> builder; - void request_loop(boost::asio::steady_timer &timer); + boost::asio::io_context io; + boost::asio::steady_timer timer{io}; + std::atomic<bool> shutdown_flag{false}; + + void request_loop(); void dump_asok_metric(boost::json::object perf_info, boost::json::value perf_values, std::string name, @@ -108,3 +116,4 @@ public: }; DaemonMetricCollector &collector_instance(); + diff --git a/src/exporter/ceph_exporter.cc b/src/exporter/ceph_exporter.cc index 2e2c16bb085..44b67c7e615 100644 --- a/src/exporter/ceph_exporter.cc +++ b/src/exporter/ceph_exporter.cc @@ -1,16 +1,31 @@ #include "common/ceph_argparse.h" #include "common/config.h" -#include "exporter/DaemonMetricCollector.h" -#include "exporter/web_server.h" +#include "common/debug.h" #include "global/global_init.h" #include "global/global_context.h" - +#include "global/signal_handler.h" +#include "exporter/DaemonMetricCollector.h" +#include "exporter/web_server.h" #include <boost/thread/thread.hpp> #include <iostream> #include <map> #include <string> +#include <atomic> +#include <chrono> +#include <thread> #define dout_context g_ceph_context +#define dout_subsys ceph_subsys_ceph_exporter + +DaemonMetricCollector &collector = collector_instance(); + +static void handle_signal(int signum) +{ + ceph_assert(signum == SIGINT || signum == SIGTERM); + derr << "*** Got signal " << sig_str(signum) << " ***" << dendl; + // Finish the DaemonMetricCollector + collector.shutdown(); +} static void usage() { std::cout << "usage: ceph-exporter [options]\n" @@ -27,7 +42,6 @@ static void usage() { } int main(int argc, char **argv) { - auto args = argv_to_vec(argc, argv); if (args.empty()) { std::cerr << argv[0] << ": -h or --help for usage" << std::endl; @@ -64,8 +78,30 @@ int main(int argc, char **argv) { } common_init_finish(g_ceph_context); + // Register signal handlers + init_async_signal_handler(); + register_async_signal_handler(SIGHUP, sighup_handler); + register_async_signal_handler_oneshot(SIGINT, handle_signal); + register_async_signal_handler_oneshot(SIGTERM, handle_signal); + + // Start the web server thread boost::thread server_thread(web_server_thread_entrypoint); - DaemonMetricCollector &collector = collector_instance(); + + // Start the DaemonMetricCollector collector.main(); + + // Interrupted. Time to terminate + unregister_async_signal_handler(SIGHUP, sighup_handler); + unregister_async_signal_handler(SIGINT, handle_signal); + unregister_async_signal_handler(SIGTERM, handle_signal); + shutdown_async_signal_handler(); + + // Stop the web server thread by interrupting it + stop_web_server(); + server_thread.interrupt(); // Interrupt the web server thread server_thread.join(); + + dout(1) << "Ceph exporter stopped" << dendl; + + return 0; } diff --git a/src/exporter/web_server.cc b/src/exporter/web_server.cc index 96cc02b389f..c01205f26bb 100644 --- a/src/exporter/web_server.cc +++ b/src/exporter/web_server.cc @@ -28,6 +28,9 @@ namespace net = boost::asio; // from <boost/asio.hpp> namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp> using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> +//common io context for the web servers +std::shared_ptr<net::io_context> global_ioc; + // Base class for common functionality class web_connection { public: @@ -43,7 +46,7 @@ protected: web_connection(net::any_io_executor executor, std::chrono::seconds timeout) : deadline_(executor, timeout) {} - // Common request processing logic + // Common request processing logic void process_request() { response_.version(request_.version()); response_.keep_alive(request_.keep_alive()); @@ -64,7 +67,7 @@ protected: write_response(); } - // Construct a response message based on the request target + // Construct a response message based on the request target void create_response() { if (request_.target() == "/") { response_.result(http::status::moved_permanently); @@ -81,7 +84,7 @@ protected: } } - // Asynchronously transmit the response message + // Asynchronously transmit the response message virtual void write_response() = 0; // Check whether we have spent enough time on this connection @@ -228,28 +231,33 @@ void https_server(tcp::acceptor &acceptor, ssl::context &ssl_ctx) { } void run_http_server(const std::string& exporter_addr, short unsigned int port) { - net::io_context ioc{1}; - tcp::acceptor acceptor{ioc, {net::ip::make_address(exporter_addr), port}}; - tcp::socket socket{ioc}; + tcp::acceptor acceptor{*global_ioc, {net::ip::make_address(exporter_addr), port}}; + tcp::socket socket{*global_ioc}; http_server(acceptor, socket); dout(1) << "HTTP server running on " << exporter_addr << ":" << port << dendl; - ioc.run(); + global_ioc->run(); } void run_https_server(const std::string& exporter_addr, short unsigned int port, const std::string& cert_file, const std::string& key_file) { - net::io_context ioc{1}; ssl::context ssl_ctx(ssl::context::tlsv13); ssl_ctx.use_certificate_chain_file(cert_file); ssl_ctx.use_private_key_file(key_file, ssl::context::pem); - tcp::acceptor acceptor{ioc, {net::ip::make_address(exporter_addr), port}}; + tcp::acceptor acceptor{*global_ioc, {net::ip::make_address(exporter_addr), port}}; https_server(acceptor, ssl_ctx); dout(1) << "HTTPS server running on " << exporter_addr << ":" << port << dendl; - ioc.run(); + global_ioc->run(); +} + +void stop_web_server() { + if (global_ioc) { + global_ioc->stop(); + dout(1) << "Ceph exporter web server stopped" << dendl; + } } void web_server_thread_entrypoint() { @@ -259,18 +267,21 @@ void web_server_thread_entrypoint() { std::string cert_file = g_conf().get_val<std::string>("exporter_cert_file"); std::string key_file = g_conf().get_val<std::string>("exporter_key_file"); + // Initialize global_ioc + global_ioc = std::make_shared<net::io_context>(1); + if (cert_file.empty() && key_file.empty()) { run_http_server(exporter_addr, port); } else { try { run_https_server(exporter_addr, port, cert_file, key_file); } catch (const std::exception &e) { - dout(1) << "Failed to start HTTPS server: " << e.what() << dendl; + derr << "Failed to start HTTPS server: " << e.what() << dendl; exit(EXIT_FAILURE); } } } catch (std::exception const &e) { - dout(1) << "Error: " << e.what() << dendl; + derr << "Error: " << e.what() << dendl; exit(EXIT_FAILURE); } } diff --git a/src/exporter/web_server.h b/src/exporter/web_server.h index c3339a8d43a..c6d4c54eca4 100644 --- a/src/exporter/web_server.h +++ b/src/exporter/web_server.h @@ -3,3 +3,4 @@ #include <string> void web_server_thread_entrypoint(); +void stop_web_server(); |