icinga2/lib/remote/eventshandler.cpp

124 lines
3.0 KiB
C++
Raw Normal View History

/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "remote/eventshandler.hpp"
#include "remote/httputility.hpp"
#include "remote/filterutility.hpp"
#include "config/configcompiler.hpp"
#include "config/expression.hpp"
2019-02-15 11:51:12 +01:00
#include "base/defer.hpp"
2019-02-15 12:32:22 +01:00
#include "base/io-engine.hpp"
#include "base/objectlock.hpp"
#include "base/json.hpp"
2019-02-15 11:51:12 +01:00
#include <boost/asio/buffer.hpp>
2019-02-15 14:36:23 +01:00
#include <boost/asio/write.hpp>
#include <boost/algorithm/string/replace.hpp>
using namespace icinga;
REGISTER_URLHANDLER("/v1/events", EventsHandler);
bool EventsHandler::HandleRequest(
2019-02-15 11:51:12 +01:00
AsioTlsStream& stream,
const ApiUser::Ptr& user,
boost::beast::http::request<boost::beast::http::string_body>& request,
const Url::Ptr& url,
boost::beast::http::response<boost::beast::http::string_body>& response,
2019-02-15 11:51:12 +01:00
const Dictionary::Ptr& params,
boost::asio::yield_context& yc,
HttpServerConnection& server
)
{
2019-02-15 11:51:12 +01:00
namespace asio = boost::asio;
namespace http = boost::beast::http;
if (url->GetPath().size() != 2)
return false;
if (request.method() != http::verb::post)
return false;
if (request.version() == 10) {
HttpUtility::SendJsonError(response, params, 400, "HTTP/1.0 not supported for event streams.");
return true;
}
Array::Ptr types = params->Get("types");
if (!types) {
HttpUtility::SendJsonError(response, params, 400, "'types' query parameter is required.");
return true;
}
{
ObjectLock olock(types);
for (const String& type : types) {
FilterUtility::CheckPermission(user, "events/" + type);
}
}
String queueName = HttpUtility::GetLastParameter(params, "queue");
if (queueName.IsEmpty()) {
HttpUtility::SendJsonError(response, params, 400, "'queue' query parameter is required.");
return true;
}
String filter = HttpUtility::GetLastParameter(params, "filter");
std::unique_ptr<Expression> ufilter;
if (!filter.IsEmpty())
ufilter = ConfigCompiler::CompileText("<API query>", filter);
/* create a new queue or update an existing one */
EventQueue::Ptr queue = EventQueue::GetByName(queueName);
if (!queue) {
queue = new EventQueue(queueName);
EventQueue::Register(queueName, queue);
}
queue->SetTypes(types->ToSet<String>());
queue->SetFilter(std::move(ufilter));
queue->AddClient(&request);
2019-02-15 11:51:12 +01:00
Defer removeClient ([&queue, &request, &queueName]() {
queue->RemoveClient(&request);
EventQueue::UnregisterIfUnused(queueName, queue);
});
server.StartStreaming();
2019-02-15 11:51:12 +01:00
response.result(http::status::ok);
response.set(http::field::content_type, "application/json");
2019-02-15 12:32:22 +01:00
{
IoBoundWorkSlot dontLockTheIoThreadWhileWriting (yc);
http::async_write(stream, response, yc);
stream.async_flush(yc);
}
2019-02-15 11:51:12 +01:00
asio::const_buffer newLine ("\n", 1);
for (;;) {
auto event (queue->WaitForEvent(&request, yc));
if (event) {
String body = JsonEncode(event);
boost::algorithm::replace_all(body, "\n", "");
2019-02-15 11:51:12 +01:00
asio::const_buffer payload (body.CStr(), body.GetLength());
2019-02-15 12:32:22 +01:00
IoBoundWorkSlot dontLockTheIoThreadWhileWriting (yc);
asio::async_write(stream, payload, yc);
asio::async_write(stream, newLine, yc);
stream.async_flush(yc);
}
}
}