diff --git a/lib/base/tlsutility.cpp b/lib/base/tlsutility.cpp index 02d677ee0..7032c7a3a 100644 --- a/lib/base/tlsutility.cpp +++ b/lib/base/tlsutility.cpp @@ -844,15 +844,7 @@ String SHA1(const String& s, bool binary) if (binary) return String(reinterpret_cast(digest), reinterpret_cast(digest + SHA_DIGEST_LENGTH)); - static const char hexdigits[] = "0123456789abcdef"; - char output[SHA_DIGEST_LENGTH*2+1]; - for (int i = 0; i < SHA_DIGEST_LENGTH; i++) { - output[2*i] = hexdigits[digest[i] >> 4]; - output[2*i + 1] = hexdigits[digest[i] & 0xf]; - } - output[2*SHA_DIGEST_LENGTH] = 0; - - return output; + return BinaryToHex(digest, SHA_DIGEST_LENGTH); } String SHA256(const String& s) @@ -930,6 +922,18 @@ String RandomString(int length) return result; } +String BinaryToHex(const unsigned char* data, size_t length) { + static const char hexdigits[] = "0123456789abcdef"; + + String output(2*length, 0); + for (int i = 0; i < SHA_DIGEST_LENGTH; i++) { + output[2 * i] = hexdigits[data[i] >> 4]; + output[2 * i + 1] = hexdigits[data[i] & 0xf]; + } + + return output; +} + bool VerifyCertificate(const std::shared_ptr &caCertificate, const std::shared_ptr &certificate, const String& crlFile) { X509_STORE *store = X509_STORE_new(); diff --git a/lib/base/tlsutility.hpp b/lib/base/tlsutility.hpp index 51bed97c1..c62f5cfad 100644 --- a/lib/base/tlsutility.hpp +++ b/lib/base/tlsutility.hpp @@ -61,6 +61,7 @@ String PBKDF2_SHA256(const String& password, const String& salt, int iterations) String SHA1(const String& s, bool binary = false); String SHA256(const String& s); String RandomString(int length); +String BinaryToHex(const unsigned char* data, size_t length); bool VerifyCertificate(const std::shared_ptr& caCertificate, const std::shared_ptr& certificate, const String& crlFile); bool IsCa(const std::shared_ptr& cacert); diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index a71974a1c..622281b0d 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -132,7 +132,7 @@ void IcingaDB::ConfigStaticInitialize() void IcingaDB::UpdateAllConfigObjects() { m_Rcon->Sync(); - m_Rcon->FireAndForgetQuery({"XADD", "icinga:schema", "MAXLEN", "1", "*", "version", "2"}, Prio::Heartbeat); + m_Rcon->FireAndForgetQuery({"XADD", "icinga:schema", "MAXLEN", "1", "*", "version", "3"}, Prio::Heartbeat); Log(LogInformation, "IcingaDB") << "Starting initial config/status dump"; double startTime = Utility::GetTime(); @@ -612,7 +612,6 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S } CustomVarObject::Ptr customVarObject = dynamic_pointer_cast(object); - auto env (GetEnvironment()); if (customVarObject) { auto vars(SerializeVars(customVarObject)); @@ -635,7 +634,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S } } - String id = HashValue(new Array(Prepend(env, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); typeCvs.emplace_back(id); Dictionary::Ptr data = new Dictionary({{objectKeyName, objectKey}, {"environment_id", m_EnvironmentId}, {"customvar_id", kv.first}}); @@ -657,7 +656,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S if (!actionUrl.IsEmpty()) { auto& actionUrls (hMSets[m_PrefixConfigObject + "action:url"]); - auto id (HashValue(new Array({env, actionUrl}))); + auto id (HashValue(new Array({m_EnvironmentId, actionUrl}))); if (runtimeUpdate || m_DumpedGlobals.ActionUrl.IsNew(id)) { actionUrls.emplace_back(std::move(id)); @@ -672,7 +671,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S if (!notesUrl.IsEmpty()) { auto& notesUrls (hMSets[m_PrefixConfigObject + "notes:url"]); - auto id (HashValue(new Array({env, notesUrl}))); + auto id (HashValue(new Array({m_EnvironmentId, notesUrl}))); if (runtimeUpdate || m_DumpedGlobals.NotesUrl.IsNew(id)) { notesUrls.emplace_back(std::move(id)); @@ -687,7 +686,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S if (!iconImage.IsEmpty()) { auto& iconImages (hMSets[m_PrefixConfigObject + "icon:image"]); - auto id (HashValue(new Array({env, iconImage}))); + auto id (HashValue(new Array({m_EnvironmentId, iconImage}))); if (runtimeUpdate || m_DumpedGlobals.IconImage.IsNew(id)) { iconImages.emplace_back(std::move(id)); @@ -725,7 +724,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S for (auto& group : groups) { auto groupObj ((*getGroup)(group)); String groupId = GetObjectIdentifier(groupObj); - String id = HashValue(new Array(Prepend(env, Prepend(GetObjectIdentifiersWithoutEnv(groupObj), GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(GetObjectIdentifiersWithoutEnv(groupObj), GetObjectIdentifiersWithoutEnv(object))))); members.emplace_back(id); Dictionary::Ptr data = new Dictionary({{objectKeyName, objectKey}, {"environment_id", m_EnvironmentId}, {typeName + "group_id", groupId}}); members.emplace_back(JsonEncode(data)); @@ -753,10 +752,10 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S rangeIds->Reserve(ranges->GetLength()); for (auto& kv : ranges) { - String rangeId = HashValue(new Array({env, kv.first, kv.second})); + String rangeId = HashValue(new Array({m_EnvironmentId, kv.first, kv.second})); rangeIds->Add(rangeId); - String id = HashValue(new Array(Prepend(env, Prepend(kv.first, Prepend(kv.second, GetObjectIdentifiersWithoutEnv(object)))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(kv.first, Prepend(kv.second, GetObjectIdentifiersWithoutEnv(object)))))); typeRanges.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"timeperiod_id", objectKey}, {"range_key", kv.first}, {"range_value", kv.second}}); typeRanges.emplace_back(JsonEncode(data)); @@ -786,7 +785,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S String includeId = GetObjectIdentifier(includeTp); includeChecksums->Add(includeId); - String id = HashValue(new Array(Prepend(env, Prepend(GetObjectIdentifiersWithoutEnv(includeTp), GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(GetObjectIdentifiersWithoutEnv(includeTp), GetObjectIdentifiersWithoutEnv(object))))); includs.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"timeperiod_id", objectKey}, {"include_id", includeId}}); includs.emplace_back(JsonEncode(data)); @@ -816,7 +815,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S String excludeId = GetObjectIdentifier(excludeTp); excludeChecksums->Add(excludeId); - String id = HashValue(new Array(Prepend(env, Prepend(GetObjectIdentifiersWithoutEnv(excludeTp), GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(GetObjectIdentifiersWithoutEnv(excludeTp), GetObjectIdentifiersWithoutEnv(object))))); excluds.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"timeperiod_id", objectKey}, {"exclude_id", excludeId}}); excluds.emplace_back(JsonEncode(data)); @@ -849,7 +848,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S for (auto& group : groups) { auto groupObj ((*getGroup)(group)); String groupId = GetObjectIdentifier(groupObj); - String id = HashValue(new Array(Prepend(env, Prepend(GetObjectIdentifiersWithoutEnv(groupObj), GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(GetObjectIdentifiersWithoutEnv(groupObj), GetObjectIdentifiersWithoutEnv(object))))); members.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"user_id", objectKey}, {"environment_id", m_EnvironmentId}, {"usergroup_id", groupId}}); members.emplace_back(JsonEncode(data)); @@ -884,7 +883,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S for (auto& user : users) { String userId = GetObjectIdentifier(user); - String id = HashValue(new Array(Prepend(env, Prepend(GetObjectIdentifiersWithoutEnv(user), GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(GetObjectIdentifiersWithoutEnv(user), GetObjectIdentifiersWithoutEnv(object))))); usrs.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}}); usrs.emplace_back(JsonEncode(data)); @@ -907,7 +906,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S auto groupMembers = usergroup->GetMembers(); std::copy(groupMembers.begin(), groupMembers.end(), std::inserter(allUsers, allUsers.begin())); - String id = HashValue(new Array(Prepend(env, Prepend("usergroup", Prepend(GetObjectIdentifiersWithoutEnv(usergroup), GetObjectIdentifiersWithoutEnv(object)))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend("usergroup", Prepend(GetObjectIdentifiersWithoutEnv(usergroup), GetObjectIdentifiersWithoutEnv(object)))))); groups.emplace_back(id); Dictionary::Ptr groupData = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"usergroup_id", usergroupId}}); groups.emplace_back(JsonEncode(groupData)); @@ -926,7 +925,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S for (auto& user : allUsers) { String userId = GetObjectIdentifier(user); - String id = HashValue(new Array(Prepend(env, Prepend("user", Prepend(GetObjectIdentifiersWithoutEnv(user), GetObjectIdentifiersWithoutEnv(object)))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend("user", Prepend(GetObjectIdentifiersWithoutEnv(user), GetObjectIdentifiersWithoutEnv(object)))))); notificationRecipients.emplace_back(id); Dictionary::Ptr data = new Dictionary({{"notification_id", objectKey}, {"environment_id", m_EnvironmentId}, {"user_id", userId}}); notificationRecipients.emplace_back(JsonEncode(data)); @@ -980,7 +979,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S values->Set("argument_key", kv.first); values->Set("environment_id", m_EnvironmentId); - String id = HashValue(new Array(Prepend(env, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); typeArgs.emplace_back(id); typeArgs.emplace_back(JsonEncode(values)); @@ -1029,7 +1028,7 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S values->Set("envvar_key", kv.first); values->Set("environment_id", m_EnvironmentId); - String id = HashValue(new Array(Prepend(env, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); + String id = HashValue(new Array(Prepend(m_EnvironmentId, Prepend(kv.first, GetObjectIdentifiersWithoutEnv(object))))); typeVars.emplace_back(id); typeVars.emplace_back(JsonEncode(values)); @@ -1219,11 +1218,11 @@ bool IcingaDB::PrepareObject(const ConfigObject::Ptr& object, Dictionary::Ptr& a String notesUrl = checkable->GetNotesUrl(); String iconImage = checkable->GetIconImage(); if (!actionUrl.IsEmpty()) - attributes->Set("action_url_id", HashValue(new Array({GetEnvironment(), actionUrl}))); + attributes->Set("action_url_id", HashValue(new Array({m_EnvironmentId, actionUrl}))); if (!notesUrl.IsEmpty()) - attributes->Set("notes_url_id", HashValue(new Array({GetEnvironment(), notesUrl}))); + attributes->Set("notes_url_id", HashValue(new Array({m_EnvironmentId, notesUrl}))); if (!iconImage.IsEmpty()) - attributes->Set("icon_image_id", HashValue(new Array({GetEnvironment(), iconImage}))); + attributes->Set("icon_image_id", HashValue(new Array({m_EnvironmentId, iconImage}))); Host::Ptr host; @@ -1556,7 +1555,7 @@ void IcingaDB::SendStateChange(const ConfigObject::Ptr& object, const CheckResul auto eventTime (cr->GetExecutionEnd()); auto eventTs (TimestampToMilliseconds(eventTime)); - Array::Ptr rawId = new Array(Prepend(GetEnvironment(), GetObjectIdentifiersWithoutEnv(object))); + Array::Ptr rawId = new Array(Prepend(m_EnvironmentId, GetObjectIdentifiersWithoutEnv(object))); rawId->Add(eventTs); std::vector xAdd ({ @@ -1636,7 +1635,7 @@ void IcingaDB::SendSentNotification( auto usersAmount (users.size()); auto sendTs (TimestampToMilliseconds(sendTime)); - Array::Ptr rawId = new Array(Prepend(GetEnvironment(), GetObjectIdentifiersWithoutEnv(notification))); + Array::Ptr rawId = new Array(Prepend(m_EnvironmentId, GetObjectIdentifiersWithoutEnv(notification))); rawId->Add(GetNotificationTypeByEnum(type)); rawId->Add(sendTs); @@ -2043,7 +2042,7 @@ void IcingaDB::SendFlappingChange(const Checkable::Ptr& checkable, double change xAdd.emplace_back("event_id"); xAdd.emplace_back(CalcEventID(checkable->IsFlapping() ? "flapping_start" : "flapping_end", checkable, startTime)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({GetEnvironment(), checkable->GetName(), startTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), startTime}))); m_Rcon->FireAndForgetQuery(std::move(xAdd), Prio::History); } @@ -2124,7 +2123,7 @@ void IcingaDB::SendAcknowledgementSet(const Checkable::Ptr& checkable, const Str xAdd.emplace_back("event_id"); xAdd.emplace_back(CalcEventID("ack_set", checkable, setTime)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({GetEnvironment(), checkable->GetName(), setTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTime}))); m_Rcon->FireAndForgetQuery(std::move(xAdd), Prio::History); } @@ -2170,7 +2169,7 @@ void IcingaDB::SendAcknowledgementCleared(const Checkable::Ptr& checkable, const xAdd.emplace_back("event_id"); xAdd.emplace_back(CalcEventID("ack_clear", checkable, setTime)); xAdd.emplace_back("id"); - xAdd.emplace_back(HashValue(new Array({GetEnvironment(), checkable->GetName(), setTime}))); + xAdd.emplace_back(HashValue(new Array({m_EnvironmentId, checkable->GetName(), setTime}))); if (!removedBy.IsEmpty()) { xAdd.emplace_back("cleared_by"); diff --git a/lib/icingadb/icingadb-utility.cpp b/lib/icingadb/icingadb-utility.cpp index 3b1713cde..769b4b5aa 100644 --- a/lib/icingadb/icingadb-utility.cpp +++ b/lib/icingadb/icingadb-utility.cpp @@ -60,11 +60,6 @@ String IcingaDB::FormatCommandLine(const Value& commandLine) return result; } -String IcingaDB::GetEnvironment() -{ - return ConfigType::GetObjectsByType()[0]->GetEnvironment(); -} - ArrayData IcingaDB::GetObjectIdentifiersWithoutEnv(const ConfigObject::Ptr& object) { Type::Ptr type = object->GetReflectionType(); @@ -77,7 +72,7 @@ ArrayData IcingaDB::GetObjectIdentifiersWithoutEnv(const ConfigObject::Ptr& obje String IcingaDB::GetObjectIdentifier(const ConfigObject::Ptr& object) { - return HashValue(new Array(Prepend(GetEnvironment(), GetObjectIdentifiersWithoutEnv(object)))); + return HashValue(new Array(Prepend(m_EnvironmentId, GetObjectIdentifiersWithoutEnv(object)))); } /** @@ -88,7 +83,7 @@ String IcingaDB::GetObjectIdentifier(const ConfigObject::Ptr& object) String IcingaDB::CalcEventID(const char* eventType, const ConfigObject::Ptr& object, double eventTime, NotificationType nt) { Array::Ptr rawId = new Array(GetObjectIdentifiersWithoutEnv(object)); - rawId->Insert(0, GetEnvironment()); + rawId->Insert(0, m_EnvironmentId); rawId->Insert(1, eventType); if (nt) { @@ -118,7 +113,7 @@ static const std::set metadataWhitelist ({"package", "source_location", * * return { * SHA1(PackObject([ - * Environment, + * EnvironmentId, * "disks", * { * "disk": {}, @@ -127,7 +122,7 @@ static const std::set metadataWhitelist ({"package", "source_location", * } * } * ])): { - * "envId": SHA1(Environment), + * "environment_id": EnvironmentId, * "name_checksum": SHA1("disks"), * "name": "disks", * "value": { @@ -151,16 +146,14 @@ Dictionary::Ptr IcingaDB::SerializeVars(const CustomVarObject::Ptr& object) return nullptr; Dictionary::Ptr res = new Dictionary(); - auto env (GetEnvironment()); - auto envChecksum (SHA1(env)); ObjectLock olock(vars); for (auto& kv : vars) { res->Set( - SHA1(PackObject((Array::Ptr)new Array({env, kv.first, kv.second}))), + SHA1(PackObject((Array::Ptr)new Array({m_EnvironmentId, kv.first, kv.second}))), (Dictionary::Ptr)new Dictionary({ - {"environment_id", envChecksum}, + {"environment_id", m_EnvironmentId}, {"name_checksum", SHA1(kv.first)}, {"name", kv.first}, {"value", JsonEncode(kv.second)}, diff --git a/lib/icingadb/icingadb.cpp b/lib/icingadb/icingadb.cpp index dec804f3d..d5f725b6f 100644 --- a/lib/icingadb/icingadb.cpp +++ b/lib/icingadb/icingadb.cpp @@ -3,11 +3,16 @@ #include "icingadb/icingadb.hpp" #include "icingadb/icingadb-ti.cpp" #include "icingadb/redisconnection.hpp" +#include "remote/apilistener.hpp" #include "remote/eventqueue.hpp" +#include "base/configuration.hpp" #include "base/json.hpp" +#include "base/tlsutility.hpp" +#include "base/utility.hpp" #include "icinga/checkable.hpp" #include "icinga/host.hpp" #include +#include #include #include @@ -18,7 +23,7 @@ using namespace icinga; using Prio = RedisConnection::QueryPriority; String IcingaDB::m_EnvironmentId; -boost::once_flag IcingaDB::m_EnvironmentIdOnce = BOOST_ONCE_INIT; +std::once_flag IcingaDB::m_EnvironmentIdOnce; REGISTER_TYPE(IcingaDB); @@ -52,9 +57,39 @@ void IcingaDB::Start(bool runtimeCreated) { ObjectImpl::Start(runtimeCreated); - boost::call_once([]() { - m_EnvironmentId = SHA1(GetEnvironment()); - }, m_EnvironmentIdOnce); + std::call_once(m_EnvironmentIdOnce, []() { + String path = Configuration::DataDir + "/icingadb.env"; + + if (Utility::PathExists(path)) { + m_EnvironmentId = Utility::LoadJsonFile(path); + + if (m_EnvironmentId.GetLength() != 2*SHA_DIGEST_LENGTH) { + throw std::runtime_error("Wrong length of stored Icinga DB environment"); + } + + for (unsigned char c : m_EnvironmentId) { + if (!std::isxdigit(c)) { + throw std::runtime_error("Stored Icinga DB environment is not a hex string"); + } + } + } else { + std::shared_ptr cert = GetX509Certificate(ApiListener::GetDefaultCaPath()); + + unsigned int n; + unsigned char digest[EVP_MAX_MD_SIZE]; + if (X509_pubkey_digest(cert.get(), EVP_sha1(), digest, &n) != 1) { + BOOST_THROW_EXCEPTION(openssl_error() + << boost::errinfo_api_function("X509_pubkey_digest") + << errinfo_openssl_error(ERR_peek_error())); + } + + m_EnvironmentId = BinaryToHex(digest, n); + + Utility::SaveJsonFile(path, 0600, m_EnvironmentId); + } + + m_EnvironmentId = m_EnvironmentId.ToLower(); + }); Log(LogInformation, "IcingaDB") << "'" << GetName() << "' started."; @@ -151,6 +186,7 @@ void IcingaDB::PublishStats() Dictionary::Ptr status = GetStats(); status->Set("config_dump_in_progress", m_ConfigDumpInProgress); status->Set("timestamp", TimestampToMilliseconds(Utility::GetTime())); + status->Set("icingadb_environment", m_EnvironmentId); std::vector query {"XADD", "icinga:stats", "MAXLEN", "1", "*"}; @@ -204,6 +240,10 @@ void IcingaDB::DumpedGlobals::Reset() m_Ids.clear(); } +String IcingaDB::GetEnvironmentId() const { + return m_EnvironmentId; +} + bool IcingaDB::DumpedGlobals::IsNew(const String& id) { std::lock_guard l (m_Mutex); diff --git a/lib/icingadb/icingadb.hpp b/lib/icingadb/icingadb.hpp index eef4267bf..fba1a2857 100644 --- a/lib/icingadb/icingadb.hpp +++ b/lib/icingadb/icingadb.hpp @@ -12,7 +12,6 @@ #include "icinga/service.hpp" #include "icinga/downtime.hpp" #include "remote/messageorigin.hpp" -#include #include #include #include @@ -40,6 +39,8 @@ public: virtual void Start(bool runtimeCreated) override; virtual void Stop(bool runtimeRemoved) override; + String GetEnvironmentId() const override; + protected: void ValidateTlsProtocolmin(const Lazy& lvalue, const ValidationUtils& utils) override; void ValidateConnectTimeout(const Lazy& lvalue, const ValidationUtils& utils) override; @@ -108,7 +109,6 @@ private: static ArrayData GetObjectIdentifiersWithoutEnv(const ConfigObject::Ptr& object); static String GetObjectIdentifier(const ConfigObject::Ptr& object); static String CalcEventID(const char* eventType, const ConfigObject::Ptr& object, double eventTime = 0, NotificationType nt = NotificationType(0)); - static String GetEnvironment(); static Dictionary::Ptr SerializeVars(const CustomVarObject::Ptr& object); static const char* GetNotificationTypeByEnum(NotificationType type); @@ -180,7 +180,7 @@ private: } m_DumpedGlobals; static String m_EnvironmentId; - static boost::once_flag m_EnvironmentIdOnce; + static std::once_flag m_EnvironmentIdOnce; }; } diff --git a/lib/icingadb/icingadb.ti b/lib/icingadb/icingadb.ti index 3e020282a..00ca95691 100644 --- a/lib/icingadb/icingadb.ti +++ b/lib/icingadb/icingadb.ti @@ -44,6 +44,10 @@ class IcingaDB : ConfigObject [config] double connect_timeout { default {{{ return DEFAULT_CONNECT_TIMEOUT; }}} }; + + [no_storage] String environment_id { + get; + }; }; }