2019-02-25 14:48:22 +01:00
|
|
|
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
|
2015-10-19 17:31:18 +02:00
|
|
|
|
|
|
|
#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"
|
2015-10-19 17:31:18 +02:00
|
|
|
#include "base/objectlock.hpp"
|
|
|
|
#include "base/json.hpp"
|
2019-02-15 11:51:12 +01:00
|
|
|
#include <boost/asio/buffer.hpp>
|
2015-10-19 17:31:18 +02:00
|
|
|
#include <boost/algorithm/string/replace.hpp>
|
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
|
|
|
REGISTER_URLHANDLER("/v1/events", EventsHandler);
|
|
|
|
|
2019-02-15 10:33:01 +01:00
|
|
|
bool EventsHandler::HandleRequest(
|
2019-02-15 11:51:12 +01:00
|
|
|
AsioTlsStream& stream,
|
2019-02-15 10:33:01 +01:00
|
|
|
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,
|
|
|
|
bool& hasStartedStreaming
|
2019-02-15 10:33:01 +01:00
|
|
|
)
|
2015-10-19 17:31:18 +02:00
|
|
|
{
|
2019-02-15 11:51:12 +01:00
|
|
|
namespace asio = boost::asio;
|
2019-02-15 10:33:01 +01:00
|
|
|
namespace http = boost::beast::http;
|
|
|
|
|
|
|
|
if (url->GetPath().size() != 2)
|
2015-10-19 17:31:18 +02:00
|
|
|
return false;
|
|
|
|
|
2019-02-15 10:33:01 +01:00
|
|
|
if (request.method() != http::verb::post)
|
2015-10-19 17:31:18 +02:00
|
|
|
return false;
|
|
|
|
|
2019-02-15 10:33:01 +01:00
|
|
|
if (request.version() == 10) {
|
2017-12-20 15:31:05 +01:00
|
|
|
HttpUtility::SendJsonError(response, params, 400, "HTTP/1.0 not supported for event streams.");
|
2015-10-19 17:31:18 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Array::Ptr types = params->Get("types");
|
|
|
|
|
|
|
|
if (!types) {
|
2017-12-20 15:31:05 +01:00
|
|
|
HttpUtility::SendJsonError(response, params, 400, "'types' query parameter is required.");
|
2015-10-19 17:31:18 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ObjectLock olock(types);
|
2016-08-25 06:19:44 +02:00
|
|
|
for (const String& type : types) {
|
2015-10-19 17:31:18 +02:00
|
|
|
FilterUtility::CheckPermission(user, "events/" + type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String queueName = HttpUtility::GetLastParameter(params, "queue");
|
|
|
|
|
|
|
|
if (queueName.IsEmpty()) {
|
2017-12-20 15:31:05 +01:00
|
|
|
HttpUtility::SendJsonError(response, params, 400, "'queue' query parameter is required.");
|
2015-10-19 17:31:18 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
String filter = HttpUtility::GetLastParameter(params, "filter");
|
|
|
|
|
2017-12-15 05:34:46 +01:00
|
|
|
std::unique_ptr<Expression> ufilter;
|
2015-10-19 17:31:18 +02:00
|
|
|
|
|
|
|
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) {
|
2016-09-02 08:51:51 +02:00
|
|
|
queue = new EventQueue(queueName);
|
2015-10-19 17:31:18 +02:00
|
|
|
EventQueue::Register(queueName, queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
queue->SetTypes(types->ToSet<String>());
|
2017-12-15 05:34:46 +01:00
|
|
|
queue->SetFilter(std::move(ufilter));
|
2015-10-19 17:31:18 +02:00
|
|
|
|
|
|
|
queue->AddClient(&request);
|
|
|
|
|
2019-02-15 11:51:12 +01:00
|
|
|
Defer removeClient ([&queue, &request, &queueName]() {
|
|
|
|
queue->RemoveClient(&request);
|
|
|
|
EventQueue::UnregisterIfUnused(queueName, queue);
|
|
|
|
});
|
|
|
|
|
|
|
|
hasStartedStreaming = true;
|
|
|
|
|
2019-02-15 10:33:01 +01:00
|
|
|
response.result(http::status::ok);
|
|
|
|
response.set(http::field::content_type, "application/json");
|
2015-10-19 17:31:18 +02:00
|
|
|
|
2019-02-15 11:51:12 +01:00
|
|
|
http::async_write(stream, response, yc);
|
|
|
|
stream.async_flush(yc);
|
|
|
|
|
|
|
|
asio::const_buffer newLine ("\n", 1);
|
|
|
|
|
2015-10-19 17:31:18 +02:00
|
|
|
for (;;) {
|
|
|
|
Dictionary::Ptr result = queue->WaitForEvent(&request);
|
|
|
|
|
|
|
|
if (!result)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
String body = JsonEncode(result);
|
|
|
|
|
|
|
|
boost::algorithm::replace_all(body, "\n", "");
|
|
|
|
|
2019-02-15 11:51:12 +01:00
|
|
|
asio::const_buffer payload (body.CStr(), body.GetLength());
|
|
|
|
|
|
|
|
stream.async_write_some(payload, yc);
|
|
|
|
stream.async_write_some(newLine, yc);
|
|
|
|
stream.async_flush(yc);
|
2015-10-19 17:31:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|