1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "remote/modifyobjecthandler.hpp"
4 #include "remote/httputility.hpp"
5 #include "remote/filterutility.hpp"
6 #include "remote/apiaction.hpp"
7 #include "base/exception.hpp"
8 #include <boost/algorithm/string/case_conv.hpp>
9 #include <set>
10
11 using namespace icinga;
12
13 REGISTER_URLHANDLER("/v1/objects", ModifyObjectHandler);
14
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)15 bool ModifyObjectHandler::HandleRequest(
16 AsioTlsStream& stream,
17 const ApiUser::Ptr& user,
18 boost::beast::http::request<boost::beast::http::string_body>& request,
19 const Url::Ptr& url,
20 boost::beast::http::response<boost::beast::http::string_body>& response,
21 const Dictionary::Ptr& params,
22 boost::asio::yield_context& yc,
23 HttpServerConnection& server
24 )
25 {
26 namespace http = boost::beast::http;
27
28 if (url->GetPath().size() < 3 || url->GetPath().size() > 4)
29 return false;
30
31 if (request.method() != http::verb::post)
32 return false;
33
34 Type::Ptr type = FilterUtility::TypeFromPluralName(url->GetPath()[2]);
35
36 if (!type) {
37 HttpUtility::SendJsonError(response, params, 400, "Invalid type specified.");
38 return true;
39 }
40
41 QueryDescription qd;
42 qd.Types.insert(type->GetName());
43 qd.Permission = "objects/modify/" + type->GetName();
44
45 params->Set("type", type->GetName());
46
47 if (url->GetPath().size() >= 4) {
48 String attr = type->GetName();
49 boost::algorithm::to_lower(attr);
50 params->Set(attr, url->GetPath()[3]);
51 }
52
53 std::vector<Value> objs;
54
55 try {
56 objs = FilterUtility::GetFilterTargets(qd, params, user);
57 } catch (const std::exception& ex) {
58 HttpUtility::SendJsonError(response, params, 404,
59 "No objects found.",
60 DiagnosticInformation(ex));
61 return true;
62 }
63
64 Value attrsVal = params->Get("attrs");
65
66 if (attrsVal.GetReflectionType() != Dictionary::TypeInstance) {
67 HttpUtility::SendJsonError(response, params, 400,
68 "Invalid type for 'attrs' attribute specified. Dictionary type is required."
69 "Or is this a POST query and you missed adding a 'X-HTTP-Method-Override: GET' header?");
70 return true;
71 }
72
73 Dictionary::Ptr attrs = attrsVal;
74
75 bool verbose = false;
76
77 if (params)
78 verbose = HttpUtility::GetLastParameter(params, "verbose");
79
80 ArrayData results;
81
82 for (const ConfigObject::Ptr& obj : objs) {
83 Dictionary::Ptr result1 = new Dictionary();
84
85 result1->Set("type", type->GetName());
86 result1->Set("name", obj->GetName());
87
88 String key;
89
90 try {
91 if (attrs) {
92 ObjectLock olock(attrs);
93 for (const Dictionary::Pair& kv : attrs) {
94 key = kv.first;
95 obj->ModifyAttribute(kv.first, kv.second);
96 }
97 }
98
99 result1->Set("code", 200);
100 result1->Set("status", "Attributes updated.");
101 } catch (const std::exception& ex) {
102 result1->Set("code", 500);
103 result1->Set("status", "Attribute '" + key + "' could not be set: " + DiagnosticInformation(ex, false));
104
105 if (verbose)
106 result1->Set("diagnostic_information", DiagnosticInformation(ex));
107 }
108
109 results.push_back(std::move(result1));
110 }
111
112 Dictionary::Ptr result = new Dictionary({
113 { "results", new Array(std::move(results)) }
114 });
115
116 response.result(http::status::ok);
117 HttpUtility::SendJsonBody(response, params, result);
118
119 return true;
120 }
121