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"
|
2019-02-15 12:32:22 +01:00
|
|
|
#include "base/io-engine.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>
|
2019-02-15 14:36:23 +01:00
|
|
|
#include <boost/asio/write.hpp>
|
2015-10-19 17:31:18 +02:00
|
|
|
#include <boost/algorithm/string/replace.hpp>
|
2019-04-05 17:34:46 +02:00
|
|
|
#include <map>
|
|
|
|
#include <set>
|
2015-10-19 17:31:18 +02:00
|
|
|
|
|
|
|
using namespace icinga;
|
|
|
|
|
|
|
|
REGISTER_URLHANDLER("/v1/events", EventsHandler);
|
|
|
|
|
2019-04-05 17:34:46 +02:00
|
|
|
const std::map<String, EventType> l_EventTypes ({
|
|
|
|
{"AcknowledgementCleared", EventType::AcknowledgementCleared},
|
|
|
|
{"AcknowledgementSet", EventType::AcknowledgementSet},
|
|
|
|
{"CheckResult", EventType::CheckResult},
|
|
|
|
{"CommentAdded", EventType::CommentAdded},
|
|
|
|
{"CommentRemoved", EventType::CommentRemoved},
|
|
|
|
{"DowntimeAdded", EventType::DowntimeAdded},
|
|
|
|
{"DowntimeRemoved", EventType::DowntimeRemoved},
|
|
|
|
{"DowntimeStarted", EventType::DowntimeStarted},
|
|
|
|
{"DowntimeTriggered", EventType::DowntimeTriggered},
|
|
|
|
{"Flapping", EventType::Flapping},
|
|
|
|
{"Notification", EventType::Notification},
|
2020-12-16 14:50:27 +01:00
|
|
|
{"StateChange", EventType::StateChange},
|
|
|
|
{"ObjectCreated", EventType::ObjectCreated},
|
|
|
|
{"ObjectDeleted", EventType::ObjectDeleted},
|
|
|
|
{"ObjectModified", EventType::ObjectModified}
|
2019-04-05 17:34:46 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
const String l_ApiQuery ("<API query>");
|
|
|
|
|
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,
|
2019-04-02 17:37:29 +02:00
|
|
|
HttpServerConnection& server
|
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;
|
|
|
|
}
|
|
|
|
|
2019-04-05 17:34:46 +02:00
|
|
|
std::set<EventType> eventTypes;
|
2015-10-19 17:31:18 +02:00
|
|
|
|
2019-04-05 17:34:46 +02:00
|
|
|
{
|
|
|
|
ObjectLock olock(types);
|
|
|
|
for (const String& type : types) {
|
|
|
|
auto typeId (l_EventTypes.find(type));
|
2015-10-19 17:31:18 +02:00
|
|
|
|
2019-04-05 17:34:46 +02:00
|
|
|
if (typeId != l_EventTypes.end()) {
|
|
|
|
eventTypes.emplace(typeId->second);
|
|
|
|
}
|
|
|
|
}
|
2015-10-19 17:31:18 +02:00
|
|
|
}
|
|
|
|
|
2019-04-05 17:34:46 +02:00
|
|
|
EventsSubscriber subscriber (std::move(eventTypes), HttpUtility::GetLastParameter(params, "filter"), l_ApiQuery);
|
2019-02-15 11:51:12 +01:00
|
|
|
|
2019-04-02 17:37:29 +02:00
|
|
|
server.StartStreaming();
|
2019-02-15 11:51:12 +01:00
|
|
|
|
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-04-08 09:43:00 +02:00
|
|
|
IoBoundWorkSlot dontLockTheIoThread (yc);
|
2019-02-15 12:32:22 +01:00
|
|
|
|
2019-04-08 09:43:00 +02:00
|
|
|
http::async_write(stream, response, yc);
|
|
|
|
stream.async_flush(yc);
|
2019-02-15 11:51:12 +01:00
|
|
|
|
|
|
|
asio::const_buffer newLine ("\n", 1);
|
|
|
|
|
2015-10-19 17:31:18 +02:00
|
|
|
for (;;) {
|
2019-04-05 17:34:46 +02:00
|
|
|
auto event (subscriber.GetInbox()->Shift(yc));
|
2015-10-19 17:31:18 +02:00
|
|
|
|
2019-04-03 09:53:45 +02:00
|
|
|
if (event) {
|
2019-04-08 09:43:00 +02:00
|
|
|
CpuBoundWork buildingResponse (yc);
|
|
|
|
|
2019-04-03 09:53:45 +02:00
|
|
|
String body = JsonEncode(event);
|
2015-10-19 17:31:18 +02:00
|
|
|
|
2019-04-03 09:53:45 +02:00
|
|
|
boost::algorithm::replace_all(body, "\n", "");
|
2019-02-15 11:51:12 +01:00
|
|
|
|
2019-04-03 09:53:45 +02:00
|
|
|
asio::const_buffer payload (body.CStr(), body.GetLength());
|
2019-02-15 12:32:22 +01:00
|
|
|
|
2019-04-08 09:43:00 +02:00
|
|
|
buildingResponse.Done();
|
2019-04-03 09:53:45 +02:00
|
|
|
|
|
|
|
asio::async_write(stream, payload, yc);
|
|
|
|
asio::async_write(stream, newLine, yc);
|
|
|
|
stream.async_flush(yc);
|
2019-04-03 09:59:45 +02:00
|
|
|
} else if (server.Disconnected()) {
|
|
|
|
return true;
|
2019-04-03 09:53:45 +02:00
|
|
|
}
|
2015-10-19 17:31:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|