1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2 
3 #include "remote/statushandler.hpp"
4 #include "remote/httputility.hpp"
5 #include "remote/filterutility.hpp"
6 #include "base/serializer.hpp"
7 #include "base/statsfunction.hpp"
8 #include "base/namespace.hpp"
9 
10 using namespace icinga;
11 
12 REGISTER_URLHANDLER("/v1/status", StatusHandler);
13 
14 class StatusTargetProvider final : public TargetProvider
15 {
16 public:
17 	DECLARE_PTR_TYPEDEFS(StatusTargetProvider);
18 
FindTargets(const String & type,const std::function<void (const Value &)> & addTarget) const19 	void FindTargets(const String& type,
20 		const std::function<void (const Value&)>& addTarget) const override
21 	{
22 		Namespace::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
23 
24 		if (statsFunctions) {
25 			ObjectLock olock(statsFunctions);
26 
27 			for (const Namespace::Pair& kv : statsFunctions)
28 				addTarget(GetTargetByName("Status", kv.first));
29 		}
30 	}
31 
GetTargetByName(const String & type,const String & name) const32 	Value GetTargetByName(const String& type, const String& name) const override
33 	{
34 		Namespace::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
35 
36 		if (!statsFunctions)
37 			BOOST_THROW_EXCEPTION(std::invalid_argument("No status functions are available."));
38 
39 		Value vfunc;
40 
41 		if (!statsFunctions->Get(name, &vfunc))
42 			BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name."));
43 
44 		Function::Ptr func = vfunc;
45 
46 		if (!func)
47 			BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name."));
48 
49 		Dictionary::Ptr status = new Dictionary();
50 		Array::Ptr perfdata = new Array();
51 		func->Invoke({ status, perfdata });
52 
53 		return new Dictionary({
54 			{ "name", name },
55 			{ "status", status },
56 			{ "perfdata", Serialize(perfdata, FAState) }
57 		});
58 	}
59 
IsValidType(const String & type) const60 	bool IsValidType(const String& type) const override
61 	{
62 		return type == "Status";
63 	}
64 
GetPluralName(const String & type) const65 	String GetPluralName(const String& type) const override
66 	{
67 		return "statuses";
68 	}
69 };
70 
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)71 bool StatusHandler::HandleRequest(
72 	AsioTlsStream& stream,
73 	const ApiUser::Ptr& user,
74 	boost::beast::http::request<boost::beast::http::string_body>& request,
75 	const Url::Ptr& url,
76 	boost::beast::http::response<boost::beast::http::string_body>& response,
77 	const Dictionary::Ptr& params,
78 	boost::asio::yield_context& yc,
79 	HttpServerConnection& server
80 )
81 {
82 	namespace http = boost::beast::http;
83 
84 	if (url->GetPath().size() > 3)
85 		return false;
86 
87 	if (request.method() != http::verb::get)
88 		return false;
89 
90 	QueryDescription qd;
91 	qd.Types.insert("Status");
92 	qd.Provider = new StatusTargetProvider();
93 	qd.Permission = "status/query";
94 
95 	params->Set("type", "Status");
96 
97 	if (url->GetPath().size() >= 3)
98 		params->Set("status", url->GetPath()[2]);
99 
100 	std::vector<Value> objs;
101 
102 	try {
103 		objs = FilterUtility::GetFilterTargets(qd, params, user);
104 	} catch (const std::exception& ex) {
105 		HttpUtility::SendJsonError(response, params, 404,
106 			"No objects found.",
107 			DiagnosticInformation(ex));
108 		return true;
109 	}
110 
111 	Dictionary::Ptr result = new Dictionary({
112 		{ "results", new Array(std::move(objs)) }
113 	});
114 
115 	response.result(http::status::ok);
116 	HttpUtility::SendJsonBody(response, params, result);
117 
118 	return true;
119 }
120 
121