diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 05f4944f6fa..be8a10ae4c4 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -280,17 +280,6 @@ static int Main() #endif /* RLIMIT_STACK */ } - /* Calculate additional global constants. */ - ScriptGlobal::Set("System.PlatformKernel", Utility::GetPlatformKernel(), true); - ScriptGlobal::Set("System.PlatformKernelVersion", Utility::GetPlatformKernelVersion(), true); - ScriptGlobal::Set("System.PlatformName", Utility::GetPlatformName(), true); - ScriptGlobal::Set("System.PlatformVersion", Utility::GetPlatformVersion(), true); - ScriptGlobal::Set("System.PlatformArchitecture", Utility::GetPlatformArchitecture(), true); - - ScriptGlobal::Set("System.BuildHostName", ICINGA_BUILD_HOST_NAME, true); - ScriptGlobal::Set("System.BuildCompilerName", ICINGA_BUILD_COMPILER_NAME, true); - ScriptGlobal::Set("System.BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION, true); - if (!autocomplete) Application::SetResourceLimits(); diff --git a/lib/base/function.hpp b/lib/base/function.hpp index fa1ce92bdbe..d52a230a1ee 100644 --- a/lib/base/function.hpp +++ b/lib/base/function.hpp @@ -60,28 +60,28 @@ class Function final : public ObjectImpl INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ - nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \ + nsp->Set(#name, sf, true); \ }, InitializePriority::RegisterFunctions) #define REGISTER_SAFE_FUNCTION(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ - nsp->SetAttribute(#name, new ConstEmbeddedNamespaceValue(sf)); \ + nsp->Set(#name, sf, true); \ }, InitializePriority::RegisterFunctions) #define REGISTER_FUNCTION_NONCONST(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ - nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \ + nsp->Set(#name, sf, false); \ }, InitializePriority::RegisterFunctions) #define REGISTER_SAFE_FUNCTION_NONCONST(ns, name, callback, args) \ INITIALIZE_ONCE_WITH_PRIORITY([]() { \ Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \ Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \ - nsp->SetAttribute(#name, new EmbeddedNamespaceValue(sf)); \ + nsp->SetAttribute(#name, sf, false); \ }, InitializePriority::RegisterFunctions) } diff --git a/lib/base/initialize.hpp b/lib/base/initialize.hpp index 94dedfaf2a9..adc995fe1b9 100644 --- a/lib/base/initialize.hpp +++ b/lib/base/initialize.hpp @@ -25,6 +25,7 @@ enum class InitializePriority { RegisterTypes, EvaluateConfigFragments, Default, + FreezeNamespaces, }; #define I2_TOKENPASTE(x, y) x ## y diff --git a/lib/base/json-script.cpp b/lib/base/json-script.cpp index cb3c03392bb..90595c88f10 100644 --- a/lib/base/json-script.cpp +++ b/lib/base/json-script.cpp @@ -24,5 +24,5 @@ INITIALIZE_ONCE([]() { jsonNS->Freeze(); Namespace::Ptr systemNS = ScriptGlobal::Get("System"); - systemNS->SetAttribute("Json", new ConstEmbeddedNamespaceValue(jsonNS)); + systemNS->Set("Json", jsonNS, true); }); diff --git a/lib/base/json.cpp b/lib/base/json.cpp index 6937f0a9bda..59066e78760 100644 --- a/lib/base/json.cpp +++ b/lib/base/json.cpp @@ -95,7 +95,7 @@ void EncodeNamespace(JsonEncoder& stateMachine, const Namespace::Pt ObjectLock olock(ns); for (const Namespace::Pair& kv : ns) { stateMachine.Key(Utility::ValidateUTF8(kv.first)); - Encode(stateMachine, kv.second->Get()); + Encode(stateMachine, kv.second.Val); } stateMachine.EndObject(); diff --git a/lib/base/logger.cpp b/lib/base/logger.cpp index 0be7279b2c0..38a2c6721b4 100644 --- a/lib/base/logger.cpp +++ b/lib/base/logger.cpp @@ -40,11 +40,11 @@ std::mutex Logger::m_UpdateMinLogSeverityMutex; Atomic Logger::m_MinLogSeverity (LogDebug); INITIALIZE_ONCE([]() { - ScriptGlobal::Set("System.LogDebug", LogDebug, true); - ScriptGlobal::Set("System.LogNotice", LogNotice, true); - ScriptGlobal::Set("System.LogInformation", LogInformation, true); - ScriptGlobal::Set("System.LogWarning", LogWarning, true); - ScriptGlobal::Set("System.LogCritical", LogCritical, true); + ScriptGlobal::Set("System.LogDebug", LogDebug); + ScriptGlobal::Set("System.LogNotice", LogNotice); + ScriptGlobal::Set("System.LogInformation", LogInformation); + ScriptGlobal::Set("System.LogWarning", LogWarning); + ScriptGlobal::Set("System.LogCritical", LogCritical); }); /** diff --git a/lib/base/math-script.cpp b/lib/base/math-script.cpp index dbc2fb28549..6cd7b0eb4f7 100644 --- a/lib/base/math-script.cpp +++ b/lib/base/math-script.cpp @@ -180,5 +180,5 @@ INITIALIZE_ONCE([]() { mathNS->Freeze(); Namespace::Ptr systemNS = ScriptGlobal::Get("System"); - systemNS->SetAttribute("Math", new ConstEmbeddedNamespaceValue(mathNS)); + systemNS->Set("Math", mathNS, true); }); diff --git a/lib/base/namespace-script.cpp b/lib/base/namespace-script.cpp index 29d23a000d6..deaae7dec2d 100644 --- a/lib/base/namespace-script.cpp +++ b/lib/base/namespace-script.cpp @@ -63,7 +63,7 @@ static Array::Ptr NamespaceValues() ArrayData values; ObjectLock olock(self); for (const Namespace::Pair& kv : self) { - values.push_back(kv.second->Get()); + values.push_back(kv.second.Val); } return new Array(std::move(values)); } diff --git a/lib/base/namespace.cpp b/lib/base/namespace.cpp index d9947f1f340..cb7c872bd7c 100644 --- a/lib/base/namespace.cpp +++ b/lib/base/namespace.cpp @@ -25,32 +25,47 @@ Namespace::Namespace(bool constValues) Value Namespace::Get(const String& field) const { - ObjectLock olock(this); - Value value; - if (!GetOwnField(field, &value)) + if (!Get(field, &value)) BOOST_THROW_EXCEPTION(ScriptError("Namespace does not contain field '" + field + "'")); return value; } bool Namespace::Get(const String& field, Value *value) const { - ObjectLock olock(this); + auto lock(ReadLockUnlessFrozen()); - auto nsVal = GetAttribute(field); + auto nsVal = m_Data.find(field); - if (!nsVal) + if (nsVal == m_Data.end()) { return false; + } - *value = nsVal->Get(DebugInfo()); + *value = nsVal->second.Val; return true; } -void Namespace::Set(const String& field, const Value& value, bool overrideFrozen) +void Namespace::Set(const String& field, const Value& value, bool isConst, const DebugInfo& debugInfo) { ObjectLock olock(this); - return SetFieldByName(field, value, overrideFrozen, DebugInfo()); + if (m_Frozen) { + BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.", debugInfo)); + } + + std::unique_lock dlock (m_DataMutex); + + auto nsVal = m_Data.find(field); + + if (nsVal == m_Data.end()) { + m_Data[field] = NamespaceValue{value, isConst}; + } else { + if (nsVal->second.Const) { + BOOST_THROW_EXCEPTION(ScriptError("Constant must not be modified.", debugInfo)); + } + + nsVal->second.Val = value; + } } /** @@ -60,39 +75,43 @@ void Namespace::Set(const String& field, const Value& value, bool overrideFrozen */ size_t Namespace::GetLength() const { - ObjectLock olock(this); + auto lock(ReadLockUnlessFrozen()); return m_Data.size(); } bool Namespace::Contains(const String& field) const { - ObjectLock olock(this); + auto lock (ReadLockUnlessFrozen()); - return HasOwnField(field); + return m_Data.find(field) != m_Data.end(); } -void Namespace::Remove(const String& field, bool overrideFrozen) +void Namespace::Remove(const String& field) { ObjectLock olock(this); - if (m_Frozen && !overrideFrozen) { + if (m_Frozen) { BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.")); } - if (!overrideFrozen) { - auto attr = GetAttribute(field); + std::unique_lock dlock (m_DataMutex); - if (dynamic_pointer_cast(attr)) { - BOOST_THROW_EXCEPTION(ScriptError("Constants must not be removed.")); - } + auto it = m_Data.find(field); + + if (it == m_Data.end()) { + return; } - RemoveAttribute(field); + if (it->second.Const) { + BOOST_THROW_EXCEPTION(ScriptError("Constants must not be removed.")); + } + + m_Data.erase(it); } /** - * Freeze the namespace, preventing further updates unless overrideFrozen is set. + * Freeze the namespace, preventing further updates. * * This only prevents inserting, replacing or deleting values from the namespace. This operation has no effect on * objects referenced by the values, these remain mutable if they were before. @@ -103,111 +122,45 @@ void Namespace::Freeze() { m_Frozen = true; } -void Namespace::RemoveAttribute(const String& field) -{ - ObjectLock olock(this); - - Namespace::Iterator it; - it = m_Data.find(field); - - if (it == m_Data.end()) - return; - - m_Data.erase(it); -} - -NamespaceValue::Ptr Namespace::GetAttribute(const String& key) const -{ - ObjectLock olock(this); - - auto it = m_Data.find(key); - - if (it == m_Data.end()) - return nullptr; - - return it->second; -} - -void Namespace::SetAttribute(const String& key, const NamespaceValue::Ptr& nsVal) +std::shared_lock Namespace::ReadLockUnlessFrozen() const { - ObjectLock olock(this); - - m_Data[key] = nsVal; + if (m_Frozen.load(std::memory_order_relaxed)) { + return std::shared_lock(); + } else { + return std::shared_lock(m_DataMutex); + } } Value Namespace::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const { - ObjectLock olock(this); + auto lock (ReadLockUnlessFrozen()); - auto nsVal = GetAttribute(field); + auto nsVal = m_Data.find(field); - if (nsVal) - return nsVal->Get(debugInfo); + if (nsVal != m_Data.end()) + return nsVal->second.Val; else return GetPrototypeField(const_cast(this), field, false, debugInfo); /* Ignore indexer not found errors similar to the Dictionary class. */ } void Namespace::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) { - ObjectLock olock(this); - - auto nsVal = GetAttribute(field); + // The override frozen parameter is mandated by the interface but ignored here. If the namespace is frozen, this + // disables locking for read operations, so it must not be modified again to ensure the consistency of the internal + // data structures. + (void) overrideFrozen; - if (!nsVal) { - if (m_Frozen && !overrideFrozen) { - BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.", debugInfo)); - } - - if (m_ConstValues) { - SetAttribute(field, new ConstEmbeddedNamespaceValue(value)); - } else { - SetAttribute(field, new EmbeddedNamespaceValue(value)); - } - } else { - nsVal->Set(value, overrideFrozen, debugInfo); - } + Set(field, value, false, debugInfo); } bool Namespace::HasOwnField(const String& field) const { - ObjectLock olock(this); - - return GetAttribute(field) != nullptr; + return Contains(field); } bool Namespace::GetOwnField(const String& field, Value *result) const { - ObjectLock olock(this); - - auto nsVal = GetAttribute(field); - - if (!nsVal) - return false; - - *result = nsVal->Get(DebugInfo()); - return true; -} - -EmbeddedNamespaceValue::EmbeddedNamespaceValue(const Value& value) - : m_Value(value) -{ } - -Value EmbeddedNamespaceValue::Get(const DebugInfo& debugInfo) const -{ - return m_Value; -} - -void EmbeddedNamespaceValue::Set(const Value& value, bool, const DebugInfo&) -{ - m_Value = value; -} - -void ConstEmbeddedNamespaceValue::Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) -{ - if (!overrideFrozen) - BOOST_THROW_EXCEPTION(ScriptError("Constant must not be modified.", debugInfo)); - - EmbeddedNamespaceValue::Set(value, overrideFrozen, debugInfo); + return Get(field, result); } Namespace::Iterator Namespace::Begin() diff --git a/lib/base/namespace.hpp b/lib/base/namespace.hpp index 492d62f0e53..94f2055d373 100644 --- a/lib/base/namespace.hpp +++ b/lib/base/namespace.hpp @@ -8,42 +8,52 @@ #include "base/shared-object.hpp" #include "base/value.hpp" #include "base/debuginfo.hpp" +#include #include #include #include +#include namespace icinga { -struct NamespaceValue : public SharedObject +struct NamespaceValue { - DECLARE_PTR_TYPEDEFS(NamespaceValue); - - virtual Value Get(const DebugInfo& debugInfo = DebugInfo()) const = 0; - virtual void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo = DebugInfo()) = 0; -}; - -struct EmbeddedNamespaceValue : public NamespaceValue -{ - EmbeddedNamespaceValue(const Value& value); - - Value Get(const DebugInfo& debugInfo) const override; - void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; - -private: - Value m_Value; + Value Val; + bool Const; }; -struct ConstEmbeddedNamespaceValue : public EmbeddedNamespaceValue -{ - using EmbeddedNamespaceValue::EmbeddedNamespaceValue; - - void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; -}; /** * A namespace. * + * ## External Locking + * + * Synchronization is handled internally, so almost all functions are safe for concurrent use without external locking. + * The only exception to this are functions returning an iterator. To use these, the caller has to acquire an ObjectLock + * on the namespace. The iterators only remain valid for as long as that ObjectLock is held. Note that this also + * includes range-based for loops. + * + * If consistency across multiple operations is required, an ObjectLock must also be acquired to prevent concurrent + * modifications. + * + * ## Internal Locking + * + * Two mutex objects are involved in locking a namespace: the recursive mutex inherited from the Object class that is + * acquired and released using the ObjectLock class and the m_DataMutex shared mutex contained directly in the + * Namespace class. The ObjectLock is used to synchronize multiple write operations against each other. The shared mutex + * is only used to ensure the consistency of the m_Data data structure. + * + * Read operations must acquire a shared lock on m_DataMutex. This prevents concurrent writes to that data structure + * but still allows concurrent reads. + * + * Write operations must first obtain an ObjectLock and then a shared lock on m_DataMutex. This order is important for + * preventing deadlocks. The ObjectLock prevents concurrent write operations while the shared lock prevents concurrent + * read operations. + * + * External read access to iterators is synchronized by the caller holding an ObjectLock. This ensures no concurrent + * write operations as these require the ObjectLock but still allows concurrent reads as m_DataMutex is not locked. + * * @ingroup base */ class Namespace final : public Object @@ -51,23 +61,19 @@ class Namespace final : public Object public: DECLARE_OBJECT(Namespace); - typedef std::map::iterator Iterator; + typedef std::map::iterator Iterator; - typedef std::map::value_type Pair; + typedef std::map::value_type Pair; explicit Namespace(bool constValues = false); Value Get(const String& field) const; bool Get(const String& field, Value *value) const; - void Set(const String& field, const Value& value, bool overrideFrozen = false); + void Set(const String& field, const Value& value, bool isConst = false, const DebugInfo& debugInfo = DebugInfo()); bool Contains(const String& field) const; - void Remove(const String& field, bool overrideFrozen = false); + void Remove(const String& field); void Freeze(); - NamespaceValue::Ptr GetAttribute(const String& field) const; - void SetAttribute(const String& field, const NamespaceValue::Ptr& nsVal); - void RemoveAttribute(const String& field); - Iterator Begin(); Iterator End(); @@ -81,9 +87,12 @@ class Namespace final : public Object static Object::Ptr GetPrototype(); private: - std::map m_Data; + std::shared_lock ReadLockUnlessFrozen() const; + + std::map m_Data; + mutable std::shared_timed_mutex m_DataMutex; bool m_ConstValues; - bool m_Frozen; + std::atomic m_Frozen; }; Namespace::Iterator begin(const Namespace::Ptr& x); diff --git a/lib/base/scriptframe.cpp b/lib/base/scriptframe.cpp index 4454d7733fb..b9725cf60e6 100644 --- a/lib/base/scriptframe.cpp +++ b/lib/base/scriptframe.cpp @@ -5,12 +5,13 @@ #include "base/namespace.hpp" #include "base/exception.hpp" #include "base/configuration.hpp" +#include "base/utility.hpp" using namespace icinga; boost::thread_specific_ptr > ScriptFrame::m_ScriptFrames; -static Namespace::Ptr l_InternalNS; +static Namespace::Ptr l_SystemNS, l_TypesNS, l_StatsNS, l_InternalNS; /* Ensure that this gets called with highest priority * and wins against other static initializers in lib/icinga, etc. @@ -19,27 +20,35 @@ static Namespace::Ptr l_InternalNS; INITIALIZE_ONCE_WITH_PRIORITY([]() { Namespace::Ptr globalNS = ScriptGlobal::GetGlobals(); - Namespace::Ptr systemNS = new Namespace(true); - systemNS->Freeze(); - globalNS->SetAttribute("System", new ConstEmbeddedNamespaceValue(systemNS)); + l_SystemNS = new Namespace(true); + l_SystemNS->Set("PlatformKernel", Utility::GetPlatformKernel()); + l_SystemNS->Set("PlatformKernelVersion", Utility::GetPlatformKernelVersion()); + l_SystemNS->Set("PlatformName", Utility::GetPlatformName()); + l_SystemNS->Set("PlatformVersion", Utility::GetPlatformVersion()); + l_SystemNS->Set("PlatformArchitecture", Utility::GetPlatformArchitecture()); + l_SystemNS->Set("BuildHostName", ICINGA_BUILD_HOST_NAME); + l_SystemNS->Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME); + l_SystemNS->Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION); + globalNS->Set("System", l_SystemNS, true); - systemNS->SetAttribute("Configuration", new EmbeddedNamespaceValue(new Configuration())); + l_SystemNS->Set("Configuration", new Configuration()); - Namespace::Ptr typesNS = new Namespace(true); - typesNS->Freeze(); - globalNS->SetAttribute("Types", new ConstEmbeddedNamespaceValue(typesNS)); + l_TypesNS = new Namespace(true); + globalNS->Set("Types", l_TypesNS, true); - Namespace::Ptr statsNS = new Namespace(true); - statsNS->Freeze(); - globalNS->SetAttribute("StatsFunctions", new ConstEmbeddedNamespaceValue(statsNS)); + l_StatsNS = new Namespace(true); + globalNS->Set("StatsFunctions", l_StatsNS, true); l_InternalNS = new Namespace(true); - globalNS->SetAttribute("Internal", new ConstEmbeddedNamespaceValue(l_InternalNS)); + globalNS->Set("Internal", l_InternalNS, true); }, InitializePriority::CreateNamespaces); -INITIALIZE_ONCE([]() { +INITIALIZE_ONCE_WITH_PRIORITY([]() { + l_SystemNS->Freeze(); + l_TypesNS->Freeze(); + l_StatsNS->Freeze(); l_InternalNS->Freeze(); -}); +}, InitializePriority::FreezeNamespaces); ScriptFrame::ScriptFrame(bool allocLocals) : Locals(allocLocals ? new Dictionary() : nullptr), Self(ScriptGlobal::GetGlobals()), Sandboxed(false), Depth(0) diff --git a/lib/base/scriptglobal.cpp b/lib/base/scriptglobal.cpp index 545c097066f..f730612b1d7 100644 --- a/lib/base/scriptglobal.cpp +++ b/lib/base/scriptglobal.cpp @@ -65,7 +65,7 @@ void ScriptGlobal::Set(const String& name, const Value& value, bool overrideFroz void ScriptGlobal::SetConst(const String& name, const Value& value) { - GetGlobals()->SetAttribute(name, new ConstEmbeddedNamespaceValue(value)); + GetGlobals()->Set(name, value, true); } bool ScriptGlobal::Exists(const String& name) @@ -93,7 +93,7 @@ void ScriptGlobal::WriteToFile(const String& filename) ObjectLock olock(m_Globals); for (const Namespace::Pair& kv : m_Globals) { - Value value = kv.second->Get(); + Value value = kv.second.Val; if (value.IsObject()) value = Convert::ToString(value); diff --git a/lib/base/scriptutils.cpp b/lib/base/scriptutils.cpp index b24cdbd4a4e..7fe856de355 100644 --- a/lib/base/scriptutils.cpp +++ b/lib/base/scriptutils.cpp @@ -71,11 +71,11 @@ enum MatchType void ScriptUtils::StaticInitialize() { - ScriptGlobal::Set("System.MatchAll", MatchAll, true); - ScriptGlobal::Set("System.MatchAny", MatchAny, true); + ScriptGlobal::Set("System.MatchAll", MatchAll); + ScriptGlobal::Set("System.MatchAny", MatchAny); - ScriptGlobal::Set("System.GlobFile", GlobFile, true); - ScriptGlobal::Set("System.GlobDirectory", GlobDirectory, true); + ScriptGlobal::Set("System.GlobFile", GlobFile); + ScriptGlobal::Set("System.GlobDirectory", GlobDirectory); } String ScriptUtils::CastString(const Value& value) diff --git a/lib/base/serializer.cpp b/lib/base/serializer.cpp index c3bd84ad137..b8b140a3a6c 100644 --- a/lib/base/serializer.cpp +++ b/lib/base/serializer.cpp @@ -131,7 +131,7 @@ static Dictionary::Ptr SerializeNamespace(const Namespace::Ptr& input, int attri ObjectLock olock(input); for (const Namespace::Pair& kv : input) { - Value val = kv.second->Get(); + Value val = kv.second.Val; stack.Push(kv.first, val); auto serialized (SerializeInternal(val, attributeTypes, stack, dryRun)); diff --git a/lib/base/sysloglogger.cpp b/lib/base/sysloglogger.cpp index 21d6f6d6aa5..fc2ec095199 100644 --- a/lib/base/sysloglogger.cpp +++ b/lib/base/sysloglogger.cpp @@ -19,26 +19,26 @@ std::map SyslogHelper::m_FacilityMap; void SyslogHelper::StaticInitialize() { - ScriptGlobal::Set("System.FacilityAuth", "LOG_AUTH", true); - ScriptGlobal::Set("System.FacilityAuthPriv", "LOG_AUTHPRIV", true); - ScriptGlobal::Set("System.FacilityCron", "LOG_CRON", true); - ScriptGlobal::Set("System.FacilityDaemon", "LOG_DAEMON", true); - ScriptGlobal::Set("System.FacilityFtp", "LOG_FTP", true); - ScriptGlobal::Set("System.FacilityKern", "LOG_KERN", true); - ScriptGlobal::Set("System.FacilityLocal0", "LOG_LOCAL0", true); - ScriptGlobal::Set("System.FacilityLocal1", "LOG_LOCAL1", true); - ScriptGlobal::Set("System.FacilityLocal2", "LOG_LOCAL2", true); - ScriptGlobal::Set("System.FacilityLocal3", "LOG_LOCAL3", true); - ScriptGlobal::Set("System.FacilityLocal4", "LOG_LOCAL4", true); - ScriptGlobal::Set("System.FacilityLocal5", "LOG_LOCAL5", true); - ScriptGlobal::Set("System.FacilityLocal6", "LOG_LOCAL6", true); - ScriptGlobal::Set("System.FacilityLocal7", "LOG_LOCAL7", true); - ScriptGlobal::Set("System.FacilityLpr", "LOG_LPR", true); - ScriptGlobal::Set("System.FacilityMail", "LOG_MAIL", true); - ScriptGlobal::Set("System.FacilityNews", "LOG_NEWS", true); - ScriptGlobal::Set("System.FacilitySyslog", "LOG_SYSLOG", true); - ScriptGlobal::Set("System.FacilityUser", "LOG_USER", true); - ScriptGlobal::Set("System.FacilityUucp", "LOG_UUCP", true); + ScriptGlobal::Set("System.FacilityAuth", "LOG_AUTH"); + ScriptGlobal::Set("System.FacilityAuthPriv", "LOG_AUTHPRIV"); + ScriptGlobal::Set("System.FacilityCron", "LOG_CRON"); + ScriptGlobal::Set("System.FacilityDaemon", "LOG_DAEMON"); + ScriptGlobal::Set("System.FacilityFtp", "LOG_FTP"); + ScriptGlobal::Set("System.FacilityKern", "LOG_KERN"); + ScriptGlobal::Set("System.FacilityLocal0", "LOG_LOCAL0"); + ScriptGlobal::Set("System.FacilityLocal1", "LOG_LOCAL1"); + ScriptGlobal::Set("System.FacilityLocal2", "LOG_LOCAL2"); + ScriptGlobal::Set("System.FacilityLocal3", "LOG_LOCAL3"); + ScriptGlobal::Set("System.FacilityLocal4", "LOG_LOCAL4"); + ScriptGlobal::Set("System.FacilityLocal5", "LOG_LOCAL5"); + ScriptGlobal::Set("System.FacilityLocal6", "LOG_LOCAL6"); + ScriptGlobal::Set("System.FacilityLocal7", "LOG_LOCAL7"); + ScriptGlobal::Set("System.FacilityLpr", "LOG_LPR"); + ScriptGlobal::Set("System.FacilityMail", "LOG_MAIL"); + ScriptGlobal::Set("System.FacilityNews", "LOG_NEWS"); + ScriptGlobal::Set("System.FacilitySyslog", "LOG_SYSLOG"); + ScriptGlobal::Set("System.FacilityUser", "LOG_USER"); + ScriptGlobal::Set("System.FacilityUucp", "LOG_UUCP"); m_FacilityMap["LOG_AUTH"] = LOG_AUTH; m_FacilityMap["LOG_AUTHPRIV"] = LOG_AUTHPRIV; diff --git a/lib/base/type.cpp b/lib/base/type.cpp index 604a07ae5b0..64a442d980c 100644 --- a/lib/base/type.cpp +++ b/lib/base/type.cpp @@ -24,7 +24,7 @@ String Type::ToString() const void Type::Register(const Type::Ptr& type) { - ScriptGlobal::Set("Types." + type->GetName(), type, true); + ScriptGlobal::Set("Types." + type->GetName(), type); } Type::Ptr Type::GetByName(const String& name) @@ -54,7 +54,7 @@ std::vector Type::GetAllTypes() ObjectLock olock(typesNS); for (const Namespace::Pair& kv : typesNS) { - Value value = kv.second->Get(); + Value value = kv.second.Val; if (value.IsObjectType()) types.push_back(value); diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index ba7ff6c3f48..a8e99861a1f 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -675,20 +675,11 @@ ExpressionResult SetConstExpression::DoEvaluate(ScriptFrame& frame, DebugHint *d { auto globals = ScriptGlobal::GetGlobals(); - auto attr = globals->GetAttribute(m_Name); - - if (dynamic_pointer_cast(attr)) { - std::ostringstream msgbuf; - msgbuf << "Value for constant '" << m_Name << "' was modified. This behaviour is deprecated.\n"; - ShowCodeLocation(msgbuf, GetDebugInfo(), false); - Log(LogWarning, msgbuf.str()); - } - ExpressionResult operandres = m_Operand->Evaluate(frame); CHECK_RESULT(operandres); Value operand = operandres.GetValue(); - globals->SetAttribute(m_Name, new ConstEmbeddedNamespaceValue(operand)); + globals->Set(m_Name, operand, true); return Empty; } diff --git a/lib/db_ido/dbquery.cpp b/lib/db_ido/dbquery.cpp index 01196a53705..1de2928431e 100644 --- a/lib/db_ido/dbquery.cpp +++ b/lib/db_ido/dbquery.cpp @@ -12,22 +12,22 @@ std::map DbQuery::m_CategoryFilterMap; void DbQuery::StaticInitialize() { - ScriptGlobal::Set("Icinga.DbCatConfig", DbCatConfig, true); - ScriptGlobal::Set("Icinga.DbCatState", DbCatState, true); - ScriptGlobal::Set("Icinga.DbCatAcknowledgement", DbCatAcknowledgement, true); - ScriptGlobal::Set("Icinga.DbCatComment", DbCatComment, true); - ScriptGlobal::Set("Icinga.DbCatDowntime", DbCatDowntime, true); - ScriptGlobal::Set("Icinga.DbCatEventHandler", DbCatEventHandler, true); - ScriptGlobal::Set("Icinga.DbCatExternalCommand", DbCatExternalCommand, true); - ScriptGlobal::Set("Icinga.DbCatFlapping", DbCatFlapping, true); - ScriptGlobal::Set("Icinga.DbCatCheck", DbCatCheck, true); - ScriptGlobal::Set("Icinga.DbCatLog", DbCatLog, true); - ScriptGlobal::Set("Icinga.DbCatNotification", DbCatNotification, true); - ScriptGlobal::Set("Icinga.DbCatProgramStatus", DbCatProgramStatus, true); - ScriptGlobal::Set("Icinga.DbCatRetention", DbCatRetention, true); - ScriptGlobal::Set("Icinga.DbCatStateHistory", DbCatStateHistory, true); - - ScriptGlobal::Set("Icinga.DbCatEverything", DbCatEverything, true); + ScriptGlobal::Set("Icinga.DbCatConfig", DbCatConfig); + ScriptGlobal::Set("Icinga.DbCatState", DbCatState); + ScriptGlobal::Set("Icinga.DbCatAcknowledgement", DbCatAcknowledgement); + ScriptGlobal::Set("Icinga.DbCatComment", DbCatComment); + ScriptGlobal::Set("Icinga.DbCatDowntime", DbCatDowntime); + ScriptGlobal::Set("Icinga.DbCatEventHandler", DbCatEventHandler); + ScriptGlobal::Set("Icinga.DbCatExternalCommand", DbCatExternalCommand); + ScriptGlobal::Set("Icinga.DbCatFlapping", DbCatFlapping); + ScriptGlobal::Set("Icinga.DbCatCheck", DbCatCheck); + ScriptGlobal::Set("Icinga.DbCatLog", DbCatLog); + ScriptGlobal::Set("Icinga.DbCatNotification", DbCatNotification); + ScriptGlobal::Set("Icinga.DbCatProgramStatus", DbCatProgramStatus); + ScriptGlobal::Set("Icinga.DbCatRetention", DbCatRetention); + ScriptGlobal::Set("Icinga.DbCatStateHistory", DbCatStateHistory); + + ScriptGlobal::Set("Icinga.DbCatEverything", DbCatEverything); m_CategoryFilterMap["DbCatConfig"] = DbCatConfig; m_CategoryFilterMap["DbCatState"] = DbCatState; diff --git a/lib/icinga/checkresult.cpp b/lib/icinga/checkresult.cpp index cb445af6c6d..07f7219c444 100644 --- a/lib/icinga/checkresult.cpp +++ b/lib/icinga/checkresult.cpp @@ -9,13 +9,13 @@ using namespace icinga; REGISTER_TYPE(CheckResult); INITIALIZE_ONCE([]() { - ScriptGlobal::Set("Icinga.ServiceOK", ServiceOK, true); - ScriptGlobal::Set("Icinga.ServiceWarning", ServiceWarning, true); - ScriptGlobal::Set("Icinga.ServiceCritical", ServiceCritical, true); - ScriptGlobal::Set("Icinga.ServiceUnknown", ServiceUnknown, true); + ScriptGlobal::Set("Icinga.ServiceOK", ServiceOK); + ScriptGlobal::Set("Icinga.ServiceWarning", ServiceWarning); + ScriptGlobal::Set("Icinga.ServiceCritical", ServiceCritical); + ScriptGlobal::Set("Icinga.ServiceUnknown", ServiceUnknown); - ScriptGlobal::Set("Icinga.HostUp", HostUp, true); - ScriptGlobal::Set("Icinga.HostDown", HostDown, true); + ScriptGlobal::Set("Icinga.HostUp", HostUp); + ScriptGlobal::Set("Icinga.HostDown", HostDown); }) double CheckResult::CalculateExecutionTime() const diff --git a/lib/icinga/cib.cpp b/lib/icinga/cib.cpp index 898b0e75fbe..ce71a59924a 100644 --- a/lib/icinga/cib.cpp +++ b/lib/icinga/cib.cpp @@ -269,7 +269,7 @@ std::pair CIB::GetFeatureStats() ObjectLock olock(statsFunctions); for (const Namespace::Pair& kv : statsFunctions) - static_cast(kv.second->Get())->Invoke({ status, perfdata }); + static_cast(kv.second.Val)->Invoke({ status, perfdata }); } return std::make_pair(status, perfdata); diff --git a/lib/icinga/downtime.cpp b/lib/icinga/downtime.cpp index e67df423ba2..cd8568590e5 100644 --- a/lib/icinga/downtime.cpp +++ b/lib/icinga/downtime.cpp @@ -31,9 +31,9 @@ INITIALIZE_ONCE(&Downtime::StaticInitialize); void Downtime::StaticInitialize() { - ScriptGlobal::Set("Icinga.DowntimeNoChildren", "DowntimeNoChildren", true); - ScriptGlobal::Set("Icinga.DowntimeTriggeredChildren", "DowntimeTriggeredChildren", true); - ScriptGlobal::Set("Icinga.DowntimeNonTriggeredChildren", "DowntimeNonTriggeredChildren", true); + ScriptGlobal::Set("Icinga.DowntimeNoChildren", "DowntimeNoChildren"); + ScriptGlobal::Set("Icinga.DowntimeTriggeredChildren", "DowntimeTriggeredChildren"); + ScriptGlobal::Set("Icinga.DowntimeNonTriggeredChildren", "DowntimeNonTriggeredChildren"); } String DowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const diff --git a/lib/icinga/icingaapplication.cpp b/lib/icinga/icingaapplication.cpp index 7e0312754e2..c20ee4cfb13 100644 --- a/lib/icinga/icingaapplication.cpp +++ b/lib/icinga/icingaapplication.cpp @@ -28,6 +28,8 @@ REGISTER_TYPE(IcingaApplication); /* Ensure that the priority is lower than the basic System namespace initialization in scriptframe.cpp. */ INITIALIZE_ONCE_WITH_PRIORITY(&IcingaApplication::StaticInitialize, InitializePriority::InitIcingaApplication); +static Namespace::Ptr l_IcingaNS; + void IcingaApplication::StaticInitialize() { /* Pre-fill global constants, can be overridden with user input later in icinga-app/icinga.cpp. */ @@ -58,11 +60,14 @@ void IcingaApplication::StaticInitialize() Namespace::Ptr globalNS = ScriptGlobal::GetGlobals(); VERIFY(globalNS); - Namespace::Ptr icingaNS = new Namespace(true); - icingaNS->Freeze(); - globalNS->SetAttribute("Icinga", new ConstEmbeddedNamespaceValue(icingaNS)); + l_IcingaNS = new Namespace(true); + globalNS->Set("Icinga", l_IcingaNS, true); } +INITIALIZE_ONCE_WITH_PRIORITY([]() { + l_IcingaNS->Freeze(); +}, InitializePriority::FreezeNamespaces); + REGISTER_STATSFUNCTION(IcingaApplication, &IcingaApplication::StatsFunc); void IcingaApplication::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata) diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index f3826ca8140..fb7bc1c7094 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -63,22 +63,22 @@ Dictionary::Ptr NotificationNameComposer::ParseName(const String& name) const void Notification::StaticInitialize() { - ScriptGlobal::Set("Icinga.OK", "OK", true); - ScriptGlobal::Set("Icinga.Warning", "Warning", true); - ScriptGlobal::Set("Icinga.Critical", "Critical", true); - ScriptGlobal::Set("Icinga.Unknown", "Unknown", true); - ScriptGlobal::Set("Icinga.Up", "Up", true); - ScriptGlobal::Set("Icinga.Down", "Down", true); - - ScriptGlobal::Set("Icinga.DowntimeStart", "DowntimeStart", true); - ScriptGlobal::Set("Icinga.DowntimeEnd", "DowntimeEnd", true); - ScriptGlobal::Set("Icinga.DowntimeRemoved", "DowntimeRemoved", true); - ScriptGlobal::Set("Icinga.Custom", "Custom", true); - ScriptGlobal::Set("Icinga.Acknowledgement", "Acknowledgement", true); - ScriptGlobal::Set("Icinga.Problem", "Problem", true); - ScriptGlobal::Set("Icinga.Recovery", "Recovery", true); - ScriptGlobal::Set("Icinga.FlappingStart", "FlappingStart", true); - ScriptGlobal::Set("Icinga.FlappingEnd", "FlappingEnd", true); + ScriptGlobal::Set("Icinga.OK", "OK"); + ScriptGlobal::Set("Icinga.Warning", "Warning"); + ScriptGlobal::Set("Icinga.Critical", "Critical"); + ScriptGlobal::Set("Icinga.Unknown", "Unknown"); + ScriptGlobal::Set("Icinga.Up", "Up"); + ScriptGlobal::Set("Icinga.Down", "Down"); + + ScriptGlobal::Set("Icinga.DowntimeStart", "DowntimeStart"); + ScriptGlobal::Set("Icinga.DowntimeEnd", "DowntimeEnd"); + ScriptGlobal::Set("Icinga.DowntimeRemoved", "DowntimeRemoved"); + ScriptGlobal::Set("Icinga.Custom", "Custom"); + ScriptGlobal::Set("Icinga.Acknowledgement", "Acknowledgement"); + ScriptGlobal::Set("Icinga.Problem", "Problem"); + ScriptGlobal::Set("Icinga.Recovery", "Recovery"); + ScriptGlobal::Set("Icinga.FlappingStart", "FlappingStart"); + ScriptGlobal::Set("Icinga.FlappingEnd", "FlappingEnd"); m_StateFilterMap["OK"] = StateFilterOK; m_StateFilterMap["Warning"] = StateFilterWarning; diff --git a/lib/icingadb/icingadb-stats.cpp b/lib/icingadb/icingadb-stats.cpp index 375d0f7cad8..476756b5a2e 100644 --- a/lib/icingadb/icingadb-stats.cpp +++ b/lib/icingadb/icingadb-stats.cpp @@ -24,7 +24,7 @@ Dictionary::Ptr IcingaDB::GetStats() for (auto& kv : statsFunctions) { - Function::Ptr func = kv.second->Get(); + Function::Ptr func = kv.second.Val; if (!func) BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name.")); diff --git a/lib/remote/variablequeryhandler.cpp b/lib/remote/variablequeryhandler.cpp index aef896e6fbb..d732d3085ce 100644 --- a/lib/remote/variablequeryhandler.cpp +++ b/lib/remote/variablequeryhandler.cpp @@ -35,7 +35,7 @@ class VariableTargetProvider final : public TargetProvider Namespace::Ptr globals = ScriptGlobal::GetGlobals(); ObjectLock olock(globals); for (const Namespace::Pair& kv : globals) { - addTarget(GetTargetForVar(kv.first, kv.second->Get())); + addTarget(GetTargetForVar(kv.first, kv.second.Val)); } } }