1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "remote/templatequeryhandler.hpp"
4 #include "remote/httputility.hpp"
5 #include "remote/filterutility.hpp"
6 #include "config/configitem.hpp"
7 #include "base/configtype.hpp"
8 #include "base/scriptglobal.hpp"
9 #include "base/logger.hpp"
10 #include <boost/algorithm/string/case_conv.hpp>
11 #include <set>
12
13 using namespace icinga;
14
15 REGISTER_URLHANDLER("/v1/templates", TemplateQueryHandler);
16
17 class TemplateTargetProvider final : public TargetProvider
18 {
19 public:
20 DECLARE_PTR_TYPEDEFS(TemplateTargetProvider);
21
GetTargetForTemplate(const ConfigItem::Ptr & item)22 static Dictionary::Ptr GetTargetForTemplate(const ConfigItem::Ptr& item)
23 {
24 DebugInfo di = item->GetDebugInfo();
25
26 return new Dictionary({
27 { "name", item->GetName() },
28 { "type", item->GetType()->GetName() },
29 { "location", new Dictionary({
30 { "path", di.Path },
31 { "first_line", di.FirstLine },
32 { "first_column", di.FirstColumn },
33 { "last_line", di.LastLine },
34 { "last_column", di.LastColumn }
35 }) }
36 });
37 }
38
FindTargets(const String & type,const std::function<void (const Value &)> & addTarget) const39 void FindTargets(const String& type,
40 const std::function<void (const Value&)>& addTarget) const override
41 {
42 Type::Ptr ptype = Type::GetByName(type);
43
44 for (const ConfigItem::Ptr& item : ConfigItem::GetItems(ptype)) {
45 if (item->IsAbstract())
46 addTarget(GetTargetForTemplate(item));
47 }
48 }
49
GetTargetByName(const String & type,const String & name) const50 Value GetTargetByName(const String& type, const String& name) const override
51 {
52 Type::Ptr ptype = Type::GetByName(type);
53
54 ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(ptype, name);
55
56 if (!item || !item->IsAbstract())
57 BOOST_THROW_EXCEPTION(std::invalid_argument("Template does not exist."));
58
59 return GetTargetForTemplate(item);
60 }
61
IsValidType(const String & type) const62 bool IsValidType(const String& type) const override
63 {
64 Type::Ptr ptype = Type::GetByName(type);
65
66 if (!ptype)
67 return false;
68
69 return ConfigObject::TypeInstance->IsAssignableFrom(ptype);
70 }
71
GetPluralName(const String & type) const72 String GetPluralName(const String& type) const override
73 {
74 return Type::GetByName(type)->GetPluralName();
75 }
76 };
77
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)78 bool TemplateQueryHandler::HandleRequest(
79 AsioTlsStream& stream,
80 const ApiUser::Ptr& user,
81 boost::beast::http::request<boost::beast::http::string_body>& request,
82 const Url::Ptr& url,
83 boost::beast::http::response<boost::beast::http::string_body>& response,
84 const Dictionary::Ptr& params,
85 boost::asio::yield_context& yc,
86 HttpServerConnection& server
87 )
88 {
89 namespace http = boost::beast::http;
90
91 if (url->GetPath().size() < 3 || url->GetPath().size() > 4)
92 return false;
93
94 if (request.method() != http::verb::get)
95 return false;
96
97 Type::Ptr type = FilterUtility::TypeFromPluralName(url->GetPath()[2]);
98
99 if (!type) {
100 HttpUtility::SendJsonError(response, params, 400, "Invalid type specified.");
101 return true;
102 }
103
104 QueryDescription qd;
105 qd.Types.insert(type->GetName());
106 qd.Permission = "templates/query/" + type->GetName();
107 qd.Provider = new TemplateTargetProvider();
108
109 params->Set("type", type->GetName());
110
111 if (url->GetPath().size() >= 4) {
112 String attr = type->GetName();
113 boost::algorithm::to_lower(attr);
114 params->Set(attr, url->GetPath()[3]);
115 }
116
117 std::vector<Value> objs;
118
119 try {
120 objs = FilterUtility::GetFilterTargets(qd, params, user, "tmpl");
121 } catch (const std::exception& ex) {
122 HttpUtility::SendJsonError(response, params, 404,
123 "No templates found.",
124 DiagnosticInformation(ex));
125 return true;
126 }
127
128 Dictionary::Ptr result = new Dictionary({
129 { "results", new Array(std::move(objs)) }
130 });
131
132 response.result(http::status::ok);
133 HttpUtility::SendJsonBody(response, params, result);
134
135 return true;
136 }
137