mirror of
				https://github.com/Icinga/icinga2.git
				synced 2025-10-31 19:24:25 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			138 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* 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"
 | |
| #include "base/defer.hpp"
 | |
| #include "base/io-engine.hpp"
 | |
| #include "base/objectlock.hpp"
 | |
| #include "base/json.hpp"
 | |
| #include <boost/asio/buffer.hpp>
 | |
| #include <boost/asio/write.hpp>
 | |
| #include <boost/algorithm/string/replace.hpp>
 | |
| #include <map>
 | |
| #include <set>
 | |
| 
 | |
| using namespace icinga;
 | |
| 
 | |
| REGISTER_URLHANDLER("/v1/events", EventsHandler);
 | |
| 
 | |
| 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},
 | |
| 	{"StateChange", EventType::StateChange},
 | |
| 	{"ObjectCreated", EventType::ObjectCreated},
 | |
| 	{"ObjectDeleted", EventType::ObjectDeleted},
 | |
| 	{"ObjectModified", EventType::ObjectModified}
 | |
| });
 | |
| 
 | |
| const String l_ApiQuery ("<API query>");
 | |
| 
 | |
| bool EventsHandler::HandleRequest(
 | |
| 	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,
 | |
| 	const Dictionary::Ptr& params,
 | |
| 	boost::asio::yield_context& yc,
 | |
| 	HttpServerConnection& server
 | |
| )
 | |
| {
 | |
| 	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;
 | |
| 	}
 | |
| 
 | |
| 	std::set<EventType> eventTypes;
 | |
| 
 | |
| 	{
 | |
| 		ObjectLock olock(types);
 | |
| 		for (const String& type : types) {
 | |
| 			auto typeId (l_EventTypes.find(type));
 | |
| 
 | |
| 			if (typeId != l_EventTypes.end()) {
 | |
| 				eventTypes.emplace(typeId->second);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	EventsSubscriber subscriber (std::move(eventTypes), HttpUtility::GetLastParameter(params, "filter"), l_ApiQuery);
 | |
| 
 | |
| 	server.StartStreaming();
 | |
| 
 | |
| 	response.result(http::status::ok);
 | |
| 	response.set(http::field::content_type, "application/json");
 | |
| 
 | |
| 	IoBoundWorkSlot dontLockTheIoThread (yc);
 | |
| 
 | |
| 	http::async_write(stream, response, yc);
 | |
| 	stream.async_flush(yc);
 | |
| 
 | |
| 	asio::const_buffer newLine ("\n", 1);
 | |
| 
 | |
| 	for (;;) {
 | |
| 		auto event (subscriber.GetInbox()->Shift(yc));
 | |
| 
 | |
| 		if (event) {
 | |
| 			CpuBoundWork buildingResponse (yc);
 | |
| 
 | |
| 			String body = JsonEncode(event);
 | |
| 
 | |
| 			boost::algorithm::replace_all(body, "\n", "");
 | |
| 
 | |
| 			asio::const_buffer payload (body.CStr(), body.GetLength());
 | |
| 
 | |
| 			buildingResponse.Done();
 | |
| 
 | |
| 			asio::async_write(stream, payload, yc);
 | |
| 			asio::async_write(stream, newLine, yc);
 | |
| 			stream.async_flush(yc);
 | |
| 		} else if (server.Disconnected()) {
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 |