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