1
1
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
2
3
3
#include " remote/objectqueryhandler.hpp"
4
+ #include " base/generator.hpp"
5
+ #include " base/json.hpp"
4
6
#include " remote/httputility.hpp"
5
7
#include " remote/filterutility.hpp"
6
8
#include " base/serializer.hpp"
9
11
#include < boost/algorithm/string/case_conv.hpp>
10
12
#include < set>
11
13
#include < unordered_map>
14
+ #include < memory>
12
15
13
16
using namespace icinga ;
14
17
@@ -144,6 +147,22 @@ bool ObjectQueryHandler::HandleRequest(
144
147
return true ;
145
148
}
146
149
150
+ bool includeUsedBy = false ;
151
+ bool includeLocation = false ;
152
+ if (umetas) {
153
+ ObjectLock olock (umetas);
154
+ for (String meta : umetas) {
155
+ if (meta == " used_by" ) {
156
+ includeUsedBy = true ;
157
+ } else if (meta == " location" ) {
158
+ includeLocation = true ;
159
+ } else {
160
+ HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for meta: " + meta);
161
+ return true ;
162
+ }
163
+ }
164
+ }
165
+
147
166
bool allJoins = HttpUtility::GetLastParameter (params, " all_joins" );
148
167
149
168
params->Set (" type" , type->GetName ());
@@ -165,10 +184,7 @@ bool ObjectQueryHandler::HandleRequest(
165
184
return true ;
166
185
}
167
186
168
- ArrayData results;
169
- results.reserve (objs.size ());
170
-
171
- std::set<String> joinAttrs;
187
+ std::set<int > joinAttrs;
172
188
std::set<String> userJoinAttrs;
173
189
174
190
if (ujoins) {
@@ -187,70 +203,63 @@ bool ObjectQueryHandler::HandleRequest(
187
203
if (!allJoins && userJoinAttrs.find (field.NavigationName ) == userJoinAttrs.end ())
188
204
continue ;
189
205
190
- joinAttrs.insert (field. Name );
206
+ joinAttrs.insert (fid );
191
207
}
192
208
193
209
std::unordered_map<Type*, std::pair<bool , std::unique_ptr<Expression>>> typePermissions;
194
210
std::unordered_map<Object*, bool > objectAccessAllowed;
195
211
196
- for (ConfigObject::Ptr obj : objs) {
212
+ auto it = objs.begin ();
213
+ auto generatorFunc = [&]() -> std::optional<Value> {
214
+ if (it == objs.end ()) {
215
+ return std::nullopt ;
216
+ }
217
+
218
+ ConfigObject::Ptr obj = *it;
219
+ ++it;
220
+
197
221
DictionaryData result1{
198
222
{ " name" , obj->GetName () },
199
223
{ " type" , obj->GetReflectionType ()->GetName () }
200
224
};
201
225
202
226
DictionaryData metaAttrs;
203
-
204
- if (umetas) {
205
- ObjectLock olock (umetas);
206
- for (String meta : umetas) {
207
- if (meta == " used_by" ) {
208
- Array::Ptr used_by = new Array ();
209
- metaAttrs.emplace_back (" used_by" , used_by);
210
-
211
- for (auto & configObj : DependencyGraph::GetChildren (obj)) {
212
- used_by->Add (new Dictionary ({
213
- { " type" , configObj->GetReflectionType ()->GetName () },
214
- { " name" , configObj->GetName () }
215
- }));
216
- }
217
- } else if (meta == " location" ) {
218
- metaAttrs.emplace_back (" location" , obj->GetSourceLocation ());
219
- } else {
220
- HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for meta: " + meta);
221
- return true ;
222
- }
227
+ if (includeUsedBy) {
228
+ Array::Ptr used_by = new Array ();
229
+ metaAttrs.emplace_back (" used_by" , used_by);
230
+
231
+ for (auto & configObj : DependencyGraph::GetChildren (obj)) {
232
+ used_by->Add (new Dictionary ({
233
+ {" type" , configObj->GetReflectionType ()->GetName ()},
234
+ {" name" , configObj->GetName ()}
235
+ }));
223
236
}
224
237
}
225
238
239
+ if (includeLocation) {
240
+ metaAttrs.emplace_back (" location" , obj->GetSourceLocation ());
241
+ }
242
+
226
243
result1.emplace_back (" meta" , new Dictionary (std::move (metaAttrs)));
227
244
228
245
try {
229
246
result1.emplace_back (" attrs" , SerializeObjectAttrs (obj, String (), uattrs, false , false ));
230
247
} catch (const ScriptError& ex) {
231
- HttpUtility::SendJsonError (response, params, 400 , ex.what ());
232
- return true ;
248
+ return new Dictionary{
249
+ {" type" , type->GetName ()},
250
+ {" name" , obj->GetName ()},
251
+ {" code" , 400 },
252
+ {" status" , ex.what ()}
253
+ };
233
254
}
234
255
235
256
DictionaryData joins;
236
257
237
- for (const String& joinAttr : joinAttrs) {
258
+ for (auto joinAttr : joinAttrs) {
238
259
Object::Ptr joinedObj;
239
- int fid = type->GetFieldId (joinAttr);
240
-
241
- if (fid < 0 ) {
242
- HttpUtility::SendJsonError (response, params, 400 , " Invalid field specified for join: " + joinAttr);
243
- return true ;
244
- }
260
+ Field field = type->GetFieldInfo (joinAttr);
245
261
246
- Field field = type->GetFieldInfo (fid);
247
-
248
- if (!(field.Attributes & FANavigation)) {
249
- HttpUtility::SendJsonError (response, params, 400 , " Not a joinable field: " + joinAttr);
250
- return true ;
251
- }
252
-
253
- joinedObj = obj->NavigateField (fid);
262
+ joinedObj = obj->NavigateField (joinAttr);
254
263
255
264
if (!joinedObj)
256
265
continue ;
@@ -303,22 +312,29 @@ bool ObjectQueryHandler::HandleRequest(
303
312
try {
304
313
joins.emplace_back (prefix, SerializeObjectAttrs (joinedObj, prefix, ujoins, true , allJoins));
305
314
} catch (const ScriptError& ex) {
306
- HttpUtility::SendJsonError (response, params, 400 , ex.what ());
307
- return true ;
315
+ return new Dictionary{
316
+ {" type" , type->GetName ()},
317
+ {" name" , obj->GetName ()},
318
+ {" code" , 400 },
319
+ {" status" , ex.what ()}
320
+ };
308
321
}
309
322
}
310
323
311
324
result1.emplace_back (" joins" , new Dictionary (std::move (joins)));
312
325
313
- results.push_back (new Dictionary (std::move (result1)));
314
- }
315
-
316
- Dictionary::Ptr result = new Dictionary ({
317
- { " results" , new Array (std::move (results)) }
318
- });
326
+ return new Dictionary{std::move (result1)};
327
+ };
319
328
320
329
response.result (http::status::ok);
321
- HttpUtility::SendJsonBody (response, params, result);
330
+ response.set (http::field::content_type, " application/json" );
331
+ response.StartStreaming ();
332
+
333
+ Dictionary::Ptr results = new Dictionary{{" results" , new ValueGenerator{generatorFunc}}};
334
+ results->Freeze ();
335
+
336
+ bool pretty = HttpUtility::GetLastParameter (params, " pretty" );
337
+ response.GetJsonEncoder (pretty).Encode (results, &yc);
322
338
323
339
return true ;
324
340
}
0 commit comments