]>
git.proxmox.com Git - ceph.git/blob - ceph/src/exporter/http_server.cc
1 #include "http_server.h"
2 #include "common/debug.h"
3 #include "common/hostname.h"
4 #include "global/global_init.h"
5 #include "global/global_context.h"
6 #include "exporter/DaemonMetricCollector.h"
8 #include <boost/asio.hpp>
9 #include <boost/beast/core.hpp>
10 #include <boost/beast/http.hpp>
11 #include <boost/beast/version.hpp>
12 #include <boost/thread/thread.hpp>
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_ceph_exporter
24 namespace beast
= boost::beast
; // from <boost/beast.hpp>
25 namespace http
= beast::http
; // from <boost/beast/http.hpp>
26 namespace net
= boost::asio
; // from <boost/asio.hpp>
27 using tcp
= boost::asio::ip::tcp
; // from <boost/asio/ip/tcp.hpp>
29 class http_connection
: public std::enable_shared_from_this
<http_connection
> {
31 http_connection(tcp::socket socket
) : socket_(std::move(socket
)) {}
33 // Initiate the asynchronous operations associated with the connection.
41 beast::flat_buffer buffer_
{8192};
42 http::request
<http::dynamic_body
> request_
;
43 http::response
<http::string_body
> response_
;
45 net::steady_timer deadline_
{socket_
.get_executor(), std::chrono::seconds(60)};
47 // Asynchronously receive a complete request message.
49 auto self
= shared_from_this();
51 http::async_read(socket_
, buffer_
, request_
,
52 [self
](beast::error_code ec
, std::size_t bytes_transferred
) {
53 boost::ignore_unused(bytes_transferred
);
55 dout(1) << "ERROR: " << ec
.message() << dendl
;
59 self
->process_request();
64 // Determine what needs to be done with the request message.
65 void process_request() {
66 response_
.version(request_
.version());
67 response_
.keep_alive(request_
.keep_alive());
69 switch (request_
.method()) {
71 response_
.result(http::status::ok
);
76 // We return responses indicating an error if
77 // we do not recognize the request method.
78 response_
.result(http::status::method_not_allowed
);
79 response_
.set(http::field::content_type
, "text/plain");
80 std::string
body("Invalid request-method '" +
81 std::string(request_
.method_string()) + "'");
82 response_
.body() = body
;
89 // Construct a response message based on the program state.
90 void create_response() {
91 if (request_
.target() == "/") {
92 response_
.set(http::field::content_type
, "text/html; charset=utf-8");
93 std::string
body("<html>\n"
94 "<head><title>Ceph Exporter</title></head>\n"
96 "<h1>Ceph Exporter</h1>\n"
97 "<p><a href='/metrics'>Metrics</a></p>"
100 response_
.body() = body
;
101 } else if (request_
.target() == "/metrics") {
102 response_
.set(http::field::content_type
, "text/plain; charset=utf-8");
103 DaemonMetricCollector
&collector
= collector_instance();
104 std::string metrics
= collector
.get_metrics();
105 response_
.body() = metrics
;
107 response_
.result(http::status::method_not_allowed
);
108 response_
.set(http::field::content_type
, "text/plain");
109 response_
.body() = "File not found \n";
113 // Asynchronously transmit the response message.
114 void write_response() {
115 auto self
= shared_from_this();
117 response_
.prepare_payload();
119 http::async_write(socket_
, response_
,
120 [self
](beast::error_code ec
, std::size_t) {
121 self
->socket_
.shutdown(tcp::socket::shutdown_send
, ec
);
122 self
->deadline_
.cancel();
124 dout(1) << "ERROR: " << ec
.message() << dendl
;
130 // Check whether we have spent enough time on this connection.
131 void check_deadline() {
132 auto self
= shared_from_this();
134 deadline_
.async_wait([self
](beast::error_code ec
) {
136 // Close socket to cancel any outstanding operation.
137 self
->socket_
.close(ec
);
143 // "Loop" forever accepting new connections.
144 void http_server(tcp::acceptor
&acceptor
, tcp::socket
&socket
) {
145 acceptor
.async_accept(socket
, [&](beast::error_code ec
) {
147 std::make_shared
<http_connection
>(std::move(socket
))->start();
148 http_server(acceptor
, socket
);
152 void http_server_thread_entrypoint() {
154 std::string exporter_addr
= g_conf().get_val
<std::string
>("exporter_addr");
155 auto const address
= net::ip::make_address(exporter_addr
);
156 unsigned short port
= g_conf().get_val
<int64_t>("exporter_http_port");
158 net::io_context ioc
{1};
160 tcp::acceptor acceptor
{ioc
, {address
, port
}};
161 tcp::socket socket
{ioc
};
162 http_server(acceptor
, socket
);
163 dout(1) << "Http server running on " << exporter_addr
<< ":" << port
<< dendl
;
165 } catch (std::exception
const &e
) {
166 dout(1) << "Error: " << e
.what() << dendl
;