1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "config/configitem.hpp"
4 #include "config/configcompilercontext.hpp"
5 #include "config/applyrule.hpp"
6 #include "config/objectrule.hpp"
7 #include "config/configcompiler.hpp"
8 #include "base/application.hpp"
9 #include "base/configtype.hpp"
10 #include "base/objectlock.hpp"
11 #include "base/convert.hpp"
12 #include "base/logger.hpp"
13 #include "base/debug.hpp"
14 #include "base/workqueue.hpp"
15 #include "base/exception.hpp"
16 #include "base/stdiostream.hpp"
17 #include "base/netstring.hpp"
18 #include "base/serializer.hpp"
19 #include "base/json.hpp"
20 #include "base/exception.hpp"
21 #include "base/function.hpp"
22 #include "base/utility.hpp"
23 #include <boost/algorithm/string/join.hpp>
24 #include <sstream>
25 #include <fstream>
26 #include <algorithm>
27 #include <random>
28
29 using namespace icinga;
30
31 std::mutex ConfigItem::m_Mutex;
32 ConfigItem::TypeMap ConfigItem::m_Items;
33 ConfigItem::TypeMap ConfigItem::m_DefaultTemplates;
34 ConfigItem::ItemList ConfigItem::m_UnnamedItems;
35 ConfigItem::IgnoredItemList ConfigItem::m_IgnoredItems;
36
37 REGISTER_FUNCTION(Internal, run_with_activation_context, &ConfigItem::RunWithActivationContext, "func");
38
39 /**
40 * Constructor for the ConfigItem class.
41 *
42 * @param type The object type.
43 * @param name The name of the item.
44 * @param unit The unit of the item.
45 * @param abstract Whether the item is a template.
46 * @param exprl Expression list for the item.
47 * @param debuginfo Debug information.
48 */
ConfigItem(Type::Ptr type,String name,bool abstract,Expression::Ptr exprl,Expression::Ptr filter,bool defaultTmpl,bool ignoreOnError,DebugInfo debuginfo,Dictionary::Ptr scope,String zone,String package)49 ConfigItem::ConfigItem(Type::Ptr type, String name,
50 bool abstract, Expression::Ptr exprl,
51 Expression::Ptr filter, bool defaultTmpl, bool ignoreOnError,
52 DebugInfo debuginfo, Dictionary::Ptr scope,
53 String zone, String package)
54 : m_Type(std::move(type)), m_Name(std::move(name)), m_Abstract(abstract),
55 m_Expression(std::move(exprl)), m_Filter(std::move(filter)),
56 m_DefaultTmpl(defaultTmpl), m_IgnoreOnError(ignoreOnError),
57 m_DebugInfo(std::move(debuginfo)), m_Scope(std::move(scope)), m_Zone(std::move(zone)),
58 m_Package(std::move(package))
59 {
60 }
61
62 /**
63 * Retrieves the type of the configuration item.
64 *
65 * @returns The type.
66 */
GetType() const67 Type::Ptr ConfigItem::GetType() const
68 {
69 return m_Type;
70 }
71
72 /**
73 * Retrieves the name of the configuration item.
74 *
75 * @returns The name.
76 */
GetName() const77 String ConfigItem::GetName() const
78 {
79 return m_Name;
80 }
81
82 /**
83 * Checks whether the item is abstract.
84 *
85 * @returns true if the item is abstract, false otherwise.
86 */
IsAbstract() const87 bool ConfigItem::IsAbstract() const
88 {
89 return m_Abstract;
90 }
91
IsDefaultTemplate() const92 bool ConfigItem::IsDefaultTemplate() const
93 {
94 return m_DefaultTmpl;
95 }
96
IsIgnoreOnError() const97 bool ConfigItem::IsIgnoreOnError() const
98 {
99 return m_IgnoreOnError;
100 }
101
102 /**
103 * Retrieves the debug information for the configuration item.
104 *
105 * @returns The debug information.
106 */
GetDebugInfo() const107 DebugInfo ConfigItem::GetDebugInfo() const
108 {
109 return m_DebugInfo;
110 }
111
GetScope() const112 Dictionary::Ptr ConfigItem::GetScope() const
113 {
114 return m_Scope;
115 }
116
GetObject() const117 ConfigObject::Ptr ConfigItem::GetObject() const
118 {
119 return m_Object;
120 }
121
122 /**
123 * Retrieves the expression list for the configuration item.
124 *
125 * @returns The expression list.
126 */
GetExpression() const127 Expression::Ptr ConfigItem::GetExpression() const
128 {
129 return m_Expression;
130 }
131
132 /**
133 * Retrieves the object filter for the configuration item.
134 *
135 * @returns The filter expression.
136 */
GetFilter() const137 Expression::Ptr ConfigItem::GetFilter() const
138 {
139 return m_Filter;
140 }
141
142 class DefaultValidationUtils final : public ValidationUtils
143 {
144 public:
ValidateName(const String & type,const String & name) const145 bool ValidateName(const String& type, const String& name) const override
146 {
147 ConfigItem::Ptr item = ConfigItem::GetByTypeAndName(Type::GetByName(type), name);
148
149 if (!item || (item && item->IsAbstract()))
150 return false;
151
152 return true;
153 }
154 };
155
156 /**
157 * Commits the configuration item by creating a ConfigObject
158 * object.
159 *
160 * @returns The ConfigObject that was created/updated.
161 */
Commit(bool discard)162 ConfigObject::Ptr ConfigItem::Commit(bool discard)
163 {
164 Type::Ptr type = GetType();
165
166 #ifdef I2_DEBUG
167 Log(LogDebug, "ConfigItem")
168 << "Commit called for ConfigItem Type=" << type->GetName() << ", Name=" << GetName();
169 #endif /* I2_DEBUG */
170
171 /* Make sure the type is valid. */
172 if (!type || !ConfigObject::TypeInstance->IsAssignableFrom(type))
173 BOOST_THROW_EXCEPTION(ScriptError("Type '" + type->GetName() + "' does not exist.", m_DebugInfo));
174
175 if (IsAbstract())
176 return nullptr;
177
178 ConfigObject::Ptr dobj = static_pointer_cast<ConfigObject>(type->Instantiate(std::vector<Value>()));
179
180 dobj->SetDebugInfo(m_DebugInfo);
181 dobj->SetZoneName(m_Zone);
182 dobj->SetPackage(m_Package);
183 dobj->SetName(m_Name);
184
185 DebugHint debugHints;
186
187 ScriptFrame frame(true, dobj);
188 if (m_Scope)
189 m_Scope->CopyTo(frame.Locals);
190 try {
191 m_Expression->Evaluate(frame, &debugHints);
192 } catch (const std::exception& ex) {
193 if (m_IgnoreOnError) {
194 Log(LogNotice, "ConfigObject")
195 << "Ignoring config object '" << m_Name << "' of type '" << type->GetName() << "' due to errors: " << DiagnosticInformation(ex);
196
197 {
198 std::unique_lock<std::mutex> lock(m_Mutex);
199 m_IgnoredItems.push_back(m_DebugInfo.Path);
200 }
201
202 return nullptr;
203 }
204
205 throw;
206 }
207
208 if (discard)
209 m_Expression.reset();
210
211 String item_name;
212 String short_name = dobj->GetShortName();
213
214 if (!short_name.IsEmpty()) {
215 item_name = short_name;
216 dobj->SetName(short_name);
217 } else
218 item_name = m_Name;
219
220 String name = item_name;
221
222 auto *nc = dynamic_cast<NameComposer *>(type.get());
223
224 if (nc) {
225 if (name.IsEmpty())
226 BOOST_THROW_EXCEPTION(ScriptError("Object name must not be empty.", m_DebugInfo));
227
228 name = nc->MakeName(name, dobj);
229
230 if (name.IsEmpty())
231 BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object"));
232 }
233
234 if (name != item_name)
235 dobj->SetShortName(item_name);
236
237 dobj->SetName(name);
238
239 Dictionary::Ptr dhint = debugHints.ToDictionary();
240
241 try {
242 DefaultValidationUtils utils;
243 dobj->Validate(FAConfig, utils);
244 } catch (ValidationError& ex) {
245 if (m_IgnoreOnError) {
246 Log(LogNotice, "ConfigObject")
247 << "Ignoring config object '" << m_Name << "' of type '" << type->GetName() << "' due to errors: " << DiagnosticInformation(ex);
248
249 {
250 std::unique_lock<std::mutex> lock(m_Mutex);
251 m_IgnoredItems.push_back(m_DebugInfo.Path);
252 }
253
254 return nullptr;
255 }
256
257 ex.SetDebugHint(dhint);
258 throw;
259 }
260
261 try {
262 dobj->OnConfigLoaded();
263 } catch (const std::exception& ex) {
264 if (m_IgnoreOnError) {
265 Log(LogNotice, "ConfigObject")
266 << "Ignoring config object '" << m_Name << "' of type '" << m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex);
267
268 {
269 std::unique_lock<std::mutex> lock(m_Mutex);
270 m_IgnoredItems.push_back(m_DebugInfo.Path);
271 }
272
273 return nullptr;
274 }
275
276 throw;
277 }
278
279 Value serializedObject;
280
281 try {
282 serializedObject = Serialize(dobj, FAConfig);
283 } catch (const CircularReferenceError& ex) {
284 BOOST_THROW_EXCEPTION(ValidationError(dobj, ex.GetPath(), "Circular references are not allowed"));
285 }
286
287 Dictionary::Ptr persistentItem = new Dictionary({
288 { "type", type->GetName() },
289 { "name", GetName() },
290 { "properties", Serialize(dobj, FAConfig) },
291 { "debug_hints", dhint },
292 { "debug_info", new Array({
293 m_DebugInfo.Path,
294 m_DebugInfo.FirstLine,
295 m_DebugInfo.FirstColumn,
296 m_DebugInfo.LastLine,
297 m_DebugInfo.LastColumn,
298 }) }
299 });
300
301 dhint.reset();
302
303 ConfigCompilerContext::GetInstance()->WriteObject(persistentItem);
304 persistentItem.reset();
305
306 dobj->Register();
307
308 m_Object = dobj;
309
310 return dobj;
311 }
312
313 /**
314 * Registers the configuration item.
315 */
Register()316 void ConfigItem::Register()
317 {
318 m_ActivationContext = ActivationContext::GetCurrentContext();
319
320 std::unique_lock<std::mutex> lock(m_Mutex);
321
322 /* If this is a non-abstract object with a composite name
323 * we register it in m_UnnamedItems instead of m_Items. */
324 if (!m_Abstract && dynamic_cast<NameComposer *>(m_Type.get()))
325 m_UnnamedItems.emplace_back(this);
326 else {
327 auto& items = m_Items[m_Type];
328
329 auto it = items.find(m_Name);
330
331 if (it != items.end()) {
332 std::ostringstream msgbuf;
333 msgbuf << "A configuration item of type '" << m_Type->GetName()
334 << "' and name '" << GetName() << "' already exists ("
335 << it->second->GetDebugInfo() << "), new declaration: " << GetDebugInfo();
336 BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str()));
337 }
338
339 m_Items[m_Type][m_Name] = this;
340
341 if (m_DefaultTmpl)
342 m_DefaultTemplates[m_Type][m_Name] = this;
343 }
344 }
345
346 /**
347 * Unregisters the configuration item.
348 */
Unregister()349 void ConfigItem::Unregister()
350 {
351 if (m_Object) {
352 m_Object->Unregister();
353 m_Object.reset();
354 }
355
356 std::unique_lock<std::mutex> lock(m_Mutex);
357 m_UnnamedItems.erase(std::remove(m_UnnamedItems.begin(), m_UnnamedItems.end(), this), m_UnnamedItems.end());
358 m_Items[m_Type].erase(m_Name);
359 m_DefaultTemplates[m_Type].erase(m_Name);
360 }
361
362 /**
363 * Retrieves a configuration item by type and name.
364 *
365 * @param type The type of the ConfigItem that is to be looked up.
366 * @param name The name of the ConfigItem that is to be looked up.
367 * @returns The configuration item.
368 */
GetByTypeAndName(const Type::Ptr & type,const String & name)369 ConfigItem::Ptr ConfigItem::GetByTypeAndName(const Type::Ptr& type, const String& name)
370 {
371 std::unique_lock<std::mutex> lock(m_Mutex);
372
373 auto it = m_Items.find(type);
374
375 if (it == m_Items.end())
376 return nullptr;
377
378 auto it2 = it->second.find(name);
379
380 if (it2 == it->second.end())
381 return nullptr;
382
383 return it2->second;
384 }
385
CommitNewItems(const ActivationContext::Ptr & context,WorkQueue & upq,std::vector<ConfigItem::Ptr> & newItems)386 bool ConfigItem::CommitNewItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems)
387 {
388 typedef std::pair<ConfigItem::Ptr, bool> ItemPair;
389 std::vector<ItemPair> items;
390
391 {
392 std::unique_lock<std::mutex> lock(m_Mutex);
393
394 for (const TypeMap::value_type& kv : m_Items) {
395 for (const ItemMap::value_type& kv2 : kv.second) {
396 if (kv2.second->m_Abstract || kv2.second->m_Object)
397 continue;
398
399 if (kv2.second->m_ActivationContext != context)
400 continue;
401
402 items.emplace_back(kv2.second, false);
403 }
404 }
405
406 ItemList newUnnamedItems;
407
408 for (const ConfigItem::Ptr& item : m_UnnamedItems) {
409 if (item->m_ActivationContext != context) {
410 newUnnamedItems.push_back(item);
411 continue;
412 }
413
414 if (item->m_Abstract || item->m_Object)
415 continue;
416
417 items.emplace_back(item, true);
418 }
419
420 m_UnnamedItems.swap(newUnnamedItems);
421 }
422
423 if (items.empty())
424 return true;
425
426 // Shuffle all items to evenly distribute them over the threads of the workqueue. This increases perfomance
427 // noticably in environments with lots of objects and available threads.
428 std::shuffle(std::begin(items), std::end(items), std::default_random_engine {});
429
430 #ifdef I2_DEBUG
431 Log(LogDebug, "configitem")
432 << "Committing " << items.size() << " new items.";
433 #endif /* I2_DEBUG */
434
435 for (const auto& ip : items)
436 newItems.push_back(ip.first);
437
438 std::set<Type::Ptr> types;
439 std::set<Type::Ptr> completed_types;
440
441 for (const Type::Ptr& type : Type::GetAllTypes()) {
442 if (ConfigObject::TypeInstance->IsAssignableFrom(type))
443 types.insert(type);
444 }
445
446 while (types.size() != completed_types.size()) {
447 for (const Type::Ptr& type : types) {
448 if (completed_types.find(type) != completed_types.end())
449 continue;
450
451 bool unresolved_dep = false;
452
453 /* skip this type (for now) if there are unresolved load dependencies */
454 for (const String& loadDep : type->GetLoadDependencies()) {
455 Type::Ptr pLoadDep = Type::GetByName(loadDep);
456 if (types.find(pLoadDep) != types.end() && completed_types.find(pLoadDep) == completed_types.end()) {
457 unresolved_dep = true;
458 break;
459 }
460 }
461
462 if (unresolved_dep)
463 continue;
464
465 int committed_items = 0;
466 upq.ParallelFor(items, [&type, &committed_items](const ItemPair& ip) {
467 const ConfigItem::Ptr& item = ip.first;
468
469 if (item->m_Type != type)
470 return;
471
472 ip.first->Commit(ip.second);
473 committed_items++;
474 });
475
476 upq.Join();
477
478 completed_types.insert(type);
479
480 #ifdef I2_DEBUG
481 if (committed_items > 0)
482 Log(LogDebug, "configitem")
483 << "Committed " << committed_items << " items of type '" << type->GetName() << "'.";
484 #endif /* I2_DEBUG */
485
486 if (upq.HasExceptions())
487 return false;
488 }
489 }
490
491 #ifdef I2_DEBUG
492 Log(LogDebug, "configitem")
493 << "Committed " << items.size() << " items.";
494 #endif /* I2_DEBUG */
495
496 completed_types.clear();
497
498 while (types.size() != completed_types.size()) {
499 for (const Type::Ptr& type : types) {
500 if (completed_types.find(type) != completed_types.end())
501 continue;
502
503 bool unresolved_dep = false;
504
505 /* skip this type (for now) if there are unresolved load dependencies */
506 for (const String& loadDep : type->GetLoadDependencies()) {
507 Type::Ptr pLoadDep = Type::GetByName(loadDep);
508 if (types.find(pLoadDep) != types.end() && completed_types.find(pLoadDep) == completed_types.end()) {
509 unresolved_dep = true;
510 break;
511 }
512 }
513
514 if (unresolved_dep)
515 continue;
516
517 int notified_items = 0;
518 upq.ParallelFor(items, [&type, ¬ified_items](const ItemPair& ip) {
519 const ConfigItem::Ptr& item = ip.first;
520
521 if (!item->m_Object || item->m_Type != type)
522 return;
523
524 try {
525 item->m_Object->OnAllConfigLoaded();
526 notified_items++;
527 } catch (const std::exception& ex) {
528 if (!item->m_IgnoreOnError)
529 throw;
530
531 Log(LogNotice, "ConfigObject")
532 << "Ignoring config object '" << item->m_Name << "' of type '" << item->m_Type->GetName() << "' due to errors: " << DiagnosticInformation(ex);
533
534 item->Unregister();
535
536 {
537 std::unique_lock<std::mutex> lock(item->m_Mutex);
538 item->m_IgnoredItems.push_back(item->m_DebugInfo.Path);
539 }
540 }
541 });
542
543 completed_types.insert(type);
544
545 upq.Join();
546
547 #ifdef I2_DEBUG
548 if (notified_items > 0)
549 Log(LogDebug, "configitem")
550 << "Sent OnAllConfigLoaded to " << notified_items << " items of type '" << type->GetName() << "'.";
551 #endif /* I2_DEBUG */
552
553 if (upq.HasExceptions())
554 return false;
555
556 notified_items = 0;
557 for (const String& loadDep : type->GetLoadDependencies()) {
558 upq.ParallelFor(items, [loadDep, &type, ¬ified_items](const ItemPair& ip) {
559 const ConfigItem::Ptr& item = ip.first;
560
561 if (!item->m_Object || item->m_Type->GetName() != loadDep)
562 return;
563
564 ActivationScope ascope(item->m_ActivationContext);
565 item->m_Object->CreateChildObjects(type);
566 notified_items++;
567 });
568 }
569
570 upq.Join();
571
572 #ifdef I2_DEBUG
573 if (notified_items > 0)
574 Log(LogDebug, "configitem")
575 << "Sent CreateChildObjects to " << notified_items << " items of type '" << type->GetName() << "'.";
576 #endif /* I2_DEBUG */
577
578 if (upq.HasExceptions())
579 return false;
580
581 // Make sure to activate any additionally generated items
582 if (!CommitNewItems(context, upq, newItems))
583 return false;
584 }
585 }
586
587 return true;
588 }
589
CommitItems(const ActivationContext::Ptr & context,WorkQueue & upq,std::vector<ConfigItem::Ptr> & newItems,bool silent)590 bool ConfigItem::CommitItems(const ActivationContext::Ptr& context, WorkQueue& upq, std::vector<ConfigItem::Ptr>& newItems, bool silent)
591 {
592 if (!silent)
593 Log(LogInformation, "ConfigItem", "Committing config item(s).");
594
595 if (!CommitNewItems(context, upq, newItems)) {
596 upq.ReportExceptions("config");
597
598 for (const ConfigItem::Ptr& item : newItems) {
599 item->Unregister();
600 }
601
602 return false;
603 }
604
605 ApplyRule::CheckMatches(silent);
606
607 if (!silent) {
608 /* log stats for external parsers */
609 typedef std::map<Type::Ptr, int> ItemCountMap;
610 ItemCountMap itemCounts;
611 for (const ConfigItem::Ptr& item : newItems) {
612 if (!item->m_Object)
613 continue;
614
615 itemCounts[item->m_Object->GetReflectionType()]++;
616 }
617
618 for (const ItemCountMap::value_type& kv : itemCounts) {
619 Log(LogInformation, "ConfigItem")
620 << "Instantiated " << kv.second << " " << (kv.second != 1 ? kv.first->GetPluralName() : kv.first->GetName()) << ".";
621 }
622 }
623
624 return true;
625 }
626
627 /**
628 * ActivateItems activates new config items.
629 *
630 * @param newItems Vector of items to be activated
631 * @param runtimeCreated Whether the objects were created by a runtime object
632 * @param mainConfigActivation Whether this is the call for activating the main configuration during startup
633 * @param withModAttrs Whether this call shall read the modified attributes file
634 * @param cookie Cookie for preventing message loops
635 * @return Whether the config activation was successful (in case of errors, exceptions are thrown)
636 */
ActivateItems(const std::vector<ConfigItem::Ptr> & newItems,bool runtimeCreated,bool mainConfigActivation,bool withModAttrs,const Value & cookie)637 bool ConfigItem::ActivateItems(const std::vector<ConfigItem::Ptr>& newItems, bool runtimeCreated,
638 bool mainConfigActivation, bool withModAttrs, const Value& cookie)
639 {
640 static std::mutex mtx;
641 std::unique_lock<std::mutex> lock(mtx);
642
643 if (withModAttrs) {
644 /* restore modified attributes */
645 if (Utility::PathExists(Configuration::ModAttrPath)) {
646 std::unique_ptr<Expression> expression = ConfigCompiler::CompileFile(Configuration::ModAttrPath);
647
648 if (expression) {
649 try {
650 ScriptFrame frame(true);
651 expression->Evaluate(frame);
652 } catch (const std::exception& ex) {
653 Log(LogCritical, "config", DiagnosticInformation(ex));
654 }
655 }
656 }
657 }
658
659 for (const ConfigItem::Ptr& item : newItems) {
660 if (!item->m_Object)
661 continue;
662
663 ConfigObject::Ptr object = item->m_Object;
664
665 if (object->IsActive())
666 continue;
667
668 #ifdef I2_DEBUG
669 Log(LogDebug, "ConfigItem")
670 << "Setting 'active' to true for object '" << object->GetName() << "' of type '" << object->GetReflectionType()->GetName() << "'";
671 #endif /* I2_DEBUG */
672
673 object->PreActivate();
674 }
675
676 if (mainConfigActivation)
677 Log(LogInformation, "ConfigItem", "Triggering Start signal for config items");
678
679 /* Activate objects in priority order. */
680 std::vector<Type::Ptr> types = Type::GetAllTypes();
681
682 std::sort(types.begin(), types.end(), [](const Type::Ptr& a, const Type::Ptr& b) {
683 if (a->GetActivationPriority() < b->GetActivationPriority())
684 return true;
685 return false;
686 });
687
688 /* Find the last logger type to be activated. */
689 Type::Ptr lastLoggerType = nullptr;
690 for (const Type::Ptr& type : types) {
691 if (Logger::TypeInstance->IsAssignableFrom(type)) {
692 lastLoggerType = type;
693 }
694 }
695
696 for (const Type::Ptr& type : types) {
697 for (const ConfigItem::Ptr& item : newItems) {
698 if (!item->m_Object)
699 continue;
700
701 ConfigObject::Ptr object = item->m_Object;
702 Type::Ptr objectType = object->GetReflectionType();
703
704 if (objectType != type)
705 continue;
706
707 #ifdef I2_DEBUG
708 Log(LogDebug, "ConfigItem")
709 << "Activating object '" << object->GetName() << "' of type '"
710 << objectType->GetName() << "' with priority "
711 << objectType->GetActivationPriority();
712 #endif /* I2_DEBUG */
713
714 object->Activate(runtimeCreated, cookie);
715 }
716
717 if (mainConfigActivation && type == lastLoggerType) {
718 /* Disable early logging configuration once the last logger type was activated. */
719 Logger::DisableEarlyLogging();
720 }
721 }
722
723 if (mainConfigActivation)
724 Log(LogInformation, "ConfigItem", "Activated all objects.");
725
726 return true;
727 }
728
RunWithActivationContext(const Function::Ptr & function)729 bool ConfigItem::RunWithActivationContext(const Function::Ptr& function)
730 {
731 ActivationScope scope;
732
733 if (!function)
734 BOOST_THROW_EXCEPTION(ScriptError("'function' argument must not be null."));
735
736 function->Invoke();
737
738 WorkQueue upq(25000, Configuration::Concurrency);
739 upq.SetName("ConfigItem::RunWithActivationContext");
740
741 std::vector<ConfigItem::Ptr> newItems;
742
743 if (!CommitItems(scope.GetContext(), upq, newItems, true))
744 return false;
745
746 if (!ActivateItems(newItems, false, false))
747 return false;
748
749 return true;
750 }
751
GetItems(const Type::Ptr & type)752 std::vector<ConfigItem::Ptr> ConfigItem::GetItems(const Type::Ptr& type)
753 {
754 std::vector<ConfigItem::Ptr> items;
755
756 std::unique_lock<std::mutex> lock(m_Mutex);
757
758 auto it = m_Items.find(type);
759
760 if (it == m_Items.end())
761 return items;
762
763 items.reserve(it->second.size());
764
765 for (const ItemMap::value_type& kv : it->second) {
766 items.push_back(kv.second);
767 }
768
769 return items;
770 }
771
GetDefaultTemplates(const Type::Ptr & type)772 std::vector<ConfigItem::Ptr> ConfigItem::GetDefaultTemplates(const Type::Ptr& type)
773 {
774 std::vector<ConfigItem::Ptr> items;
775
776 std::unique_lock<std::mutex> lock(m_Mutex);
777
778 auto it = m_DefaultTemplates.find(type);
779
780 if (it == m_DefaultTemplates.end())
781 return items;
782
783 items.reserve(it->second.size());
784
785 for (const ItemMap::value_type& kv : it->second) {
786 items.push_back(kv.second);
787 }
788
789 return items;
790 }
791
RemoveIgnoredItems(const String & allowedConfigPath)792 void ConfigItem::RemoveIgnoredItems(const String& allowedConfigPath)
793 {
794 std::unique_lock<std::mutex> lock(m_Mutex);
795
796 for (const String& path : m_IgnoredItems) {
797 if (path.Find(allowedConfigPath) == String::NPos)
798 continue;
799
800 Log(LogNotice, "ConfigItem")
801 << "Removing ignored item path '" << path << "'.";
802
803 (void) unlink(path.CStr());
804 }
805
806 m_IgnoredItems.clear();
807 }
808