diff --git a/CMakeLists.txt b/CMakeLists.txt
index bfc558769..1eefc9938 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,13 @@ option(ICINGA2_WITH_NOTIFICATION "Build the notification module" ON)
option(ICINGA2_WITH_PERFDATA "Build the perfdata module" ON)
option(ICINGA2_WITH_TESTS "Run unit tests" ON)
+# IcingaDB only is supported on modern Linux/Unix master systems
+if(NOT WIN32)
+ option(ICINGA2_WITH_ICINGADB "Build the IcingaDB module" ON)
+else()
+ option(ICINGA2_WITH_ICINGADB "Build the IcingaDB module" OFF)
+endif()
+
option (USE_SYSTEMD
"Configure icinga as native systemd service instead of a SysV initscript" OFF)
@@ -203,7 +210,6 @@ if(HAVE_SYSTEMD)
list(APPEND base_DEPS systemd)
endif()
-
if(EDITLINE_FOUND)
list(APPEND base_DEPS ${EDITLINE_LIBRARIES})
include_directories(${EDITLINE_INCLUDE_DIR})
diff --git a/doc/09-object-types.md b/doc/09-object-types.md
index 40f161bc4..efe796e5c 100644
--- a/doc/09-object-types.md
+++ b/doc/09-object-types.md
@@ -1379,6 +1379,30 @@ Configuration Attributes:
vars | Dictionary | **Optional.** A dictionary containing custom variables that are available globally.
environment | String | **Optional.** Specify the Icinga environment. This overrides the `Environment` constant specified in the configuration or on the CLI with `--define`. Defaults to empty.
+
+### IcingaDB
+
+The IcingaDB object implements the [icingadb feauture](14-features.md#core-backends-icingadb).
+
+Example:
+
+```
+object IcingaDB "icingadb" {
+ //host = "127.0.0.1"
+ //port = 6379
+ //password = "xxx"
+}
+```
+
+Configuration Attributes:
+
+ Name | Type | Description
+ --------------------------|-----------------------|----------------------------------
+ host | String | **Optional.** Redis host for IcingaDB. Defaults to `127.0.0.1`.
+ port | Number | **Optional.** Redis port for IcingaDB. Defaults to `6379`.
+ path | String | **Optional.** Redix unix socket path. Can be used instead of `host` and `port` attributes.
+ password | String | **Optional.** Redis auth password for IcingaDB.
+
### IdoMySqlConnection
IDO database adapter for MySQL.
diff --git a/doc/14-features.md b/doc/14-features.md
index c119abd91..4b56737bf 100644
--- a/doc/14-features.md
+++ b/doc/14-features.md
@@ -44,6 +44,30 @@ By default, log files will be rotated daily.
The REST API is documented [here](12-icinga2-api.md#icinga2-api) as a core feature.
+### Icinga DB
+
+Icinga DB provides a new core backend and aims to replace the IDO backend
+output. It consists of different components:
+
+* Icinga 2 provides the `icingadb` feature which stores monitoring data in a memory database
+* The [IcingaDB service](https://github.com/icinga/icingadb) collects and synchronizes monitoring data into its backend
+* Icinga Web reads monitoring data from the new IcingaDB backend
+
+Requirements:
+
+* Local Redis instance
+* MySQL/MariaDB server with `icingadb` database, user and schema imports
+* Icinga 2's `icingadb` feature enabled
+* IcingaDB service requires Redis and MySQL/MariaDB server
+* Icinga Web module
+
+> TODO: Detailed instructions.
+
+```
+icinga2 feature enable icingadb
+```
+
+
### IDO Database (DB IDO)
The IDO (Icinga Data Output) feature for Icinga 2 takes care of exporting all
diff --git a/doc/15-troubleshooting.md b/doc/15-troubleshooting.md
index 5e7cc43ae..3ae53ce4f 100644
--- a/doc/15-troubleshooting.md
+++ b/doc/15-troubleshooting.md
@@ -1626,9 +1626,9 @@ it is valid to just sync their zones via the config sync.
The following restores the Zone/Endpoint objects as config objects outside of `zones.d`
in your master/satellite's zones.conf with rendering them as external objects in the Director.
-[Example](06-distributed-monitoring.md#three-levels-with-masters-satellites-and-agents)
+[Example](06-distributed-monitoring.md#distributed-monitoring-scenarios-master-satellite-agents)
for a 3 level setup with the masters and satellites knowing about the zone hierarchy
-outside defined in [zones.conf](#zones-conf):
+outside defined in [zones.conf](04-configuration.md#zones-conf):
```
object Endpoint "icinga-master1.localdomain" {
diff --git a/doc/16-upgrading-icinga-2.md b/doc/16-upgrading-icinga-2.md
index 7dacfb764..95e08a2d7 100644
--- a/doc/16-upgrading-icinga-2.md
+++ b/doc/16-upgrading-icinga-2.md
@@ -188,7 +188,7 @@ being set but no `zone` defined.
The most convenient way with e.g. managing the objects in `conf.d`
is to move them into the `master` zone. Please continue in the
-[troubleshooting docs](#troubleshooting-cluster-command-endpoint-errors-agent-hosts-command-endpoint-zone)
+[troubleshooting docs](15-troubleshooting.md#troubleshooting-cluster-command-endpoint-errors-agent-hosts-command-endpoint-zone)
for further instructions.
#### Config Sync
diff --git a/etc/icinga2/features-available/icingadb.conf b/etc/icinga2/features-available/icingadb.conf
new file mode 100644
index 000000000..9fe55ec8e
--- /dev/null
+++ b/etc/icinga2/features-available/icingadb.conf
@@ -0,0 +1,5 @@
+object IcingaDB "icingadb" {
+ //host = "127.0.0.1"
+ //port = 6379
+ //password = "xxx"
+}
diff --git a/icinga-app/CMakeLists.txt b/icinga-app/CMakeLists.txt
index ee3443b28..ef71ad999 100644
--- a/icinga-app/CMakeLists.txt
+++ b/icinga-app/CMakeLists.txt
@@ -53,6 +53,10 @@ if(ICINGA2_WITH_PERFDATA)
list(APPEND icinga_app_SOURCES $)
endif()
+if(ICINGA2_WITH_ICINGADB)
+ list(APPEND icinga_app_SOURCES $)
+endif()
+
add_executable(icinga-app
$
${base_OBJS}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 004fc154c..aadbb39ad 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -53,4 +53,8 @@ if(ICINGA2_WITH_PERFDATA)
add_subdirectory(perfdata)
endif()
+if(ICINGA2_WITH_ICINGADB)
+ add_subdirectory(icingadb)
+endif()
+
set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE)
diff --git a/lib/icinga/checkable-check.cpp b/lib/icinga/checkable-check.cpp
index 02bc8fc91..94940b29f 100644
--- a/lib/icinga/checkable-check.cpp
+++ b/lib/icinga/checkable-check.cpp
@@ -300,6 +300,7 @@ void Checkable::ProcessCheckResult(const CheckResult::Ptr& cr, const MessageOrig
if (hardChange || is_volatile) {
SetLastHardStateRaw(new_state);
SetLastHardStateChange(now);
+ SetLastHardStatesRaw(GetLastHardStatesRaw() / 100u + new_state * 100u);
}
if (!IsStateOK(new_state))
diff --git a/lib/icinga/checkable.hpp b/lib/icinga/checkable.hpp
index 032910adb..498cb1d8f 100644
--- a/lib/icinga/checkable.hpp
+++ b/lib/icinga/checkable.hpp
@@ -39,23 +39,6 @@ enum CheckableType
CheckableService
};
-/**
- * Severity Flags
- *
- * @ingroup icinga
- */
-enum SeverityFlag
-{
- SeverityFlagDowntime = 1,
- SeverityFlagAcknowledgement = 2,
- SeverityFlagHostDown = 4,
- SeverityFlagUnhandled = 8,
- SeverityFlagPending = 16,
- SeverityFlagWarning = 32,
- SeverityFlagUnknown = 64,
- SeverityFlagCritical = 128,
-};
-
class CheckCommand;
class EventCommand;
class Dependency;
diff --git a/lib/icinga/checkable.ti b/lib/icinga/checkable.ti
index a920d2589..07a946258 100644
--- a/lib/icinga/checkable.ti
+++ b/lib/icinga/checkable.ti
@@ -105,6 +105,9 @@ abstract class Checkable : CustomVarObject
[state, enum, no_user_view, no_user_modify] ServiceState last_hard_state_raw {
default {{{ return ServiceUnknown; }}}
};
+ [state, no_user_view, no_user_modify] "unsigned short" last_hard_states_raw {
+ default {{{ return /* current */ 99 * 100 + /* previous */ 99; }}}
+ };
[state, enum] StateType last_state_type {
default {{{ return StateTypeSoft; }}}
};
diff --git a/lib/icinga/compatutility.cpp b/lib/icinga/compatutility.cpp
index 305d3b247..40c01f397 100644
--- a/lib/icinga/compatutility.cpp
+++ b/lib/icinga/compatutility.cpp
@@ -249,7 +249,7 @@ std::set CompatUtility::GetCheckableNotificationUserGroups(const
return usergroups;
}
-/* Used in DB IDO, StatusDataWriter, Livestatus, CompatLogger, GelfWriter. */
+/* Used in DB IDO, StatusDataWriter, Livestatus, CompatLogger, GelfWriter, IcingaDB. */
String CompatUtility::GetCheckResultOutput(const CheckResult::Ptr& cr)
{
if (!cr)
@@ -264,7 +264,7 @@ String CompatUtility::GetCheckResultOutput(const CheckResult::Ptr& cr)
return raw_output.SubStr(0, line_end);
}
-/* Used in DB IDO, StatusDataWriter and Livestatus. */
+/* Used in DB IDO, StatusDataWriter and Livestatus, IcingaDB. */
String CompatUtility::GetCheckResultLongOutput(const CheckResult::Ptr& cr)
{
if (!cr)
diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp
index 9744eed46..7bb1c434d 100644
--- a/lib/icinga/host.cpp
+++ b/lib/icinga/host.cpp
@@ -164,32 +164,39 @@ HostState Host::GetLastHardState() const
return CalculateState(GetLastHardStateRaw());
}
-/* keep in sync with Service::GetSeverity() */
+/* keep in sync with Service::GetSeverity()
+ * One could think it may be smart to use an enum and some bitmask math here.
+ * But the only thing the consuming icingaweb2 cares about is being able to
+ * sort by severity. It is therefore easier to keep them seperated here. */
int Host::GetSeverity() const
{
int severity = 0;
ObjectLock olock(this);
- ServiceState state = GetStateRaw();
+ HostState state = GetState();
- /* OK/Warning = Up, Critical/Unknownb = Down */
- if (!HasBeenChecked())
- severity |= SeverityFlagPending;
- else if (state == ServiceUnknown)
- severity |= SeverityFlagCritical;
- else if (state == ServiceCritical)
- severity |= SeverityFlagCritical;
+ if (!HasBeenChecked()) {
+ severity = 16;
+ } else if (state == HostUp) {
+ severity = 0;
+ } else {
+ if (IsReachable())
+ severity = 64;
+ else
+ severity = 32;
- if (IsInDowntime())
- severity |= SeverityFlagDowntime;
- else if (IsAcknowledged())
- severity |= SeverityFlagAcknowledgement;
- else
- severity |= SeverityFlagUnhandled;
+ if (IsAcknowledged())
+ severity += 512;
+ else if (IsInDowntime())
+ severity += 256;
+ else
+ severity += 2048;
+ }
olock.Unlock();
return severity;
+
}
bool Host::IsStateOK(ServiceState state) const
diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp
index e420b64c3..ec80aa6dc 100644
--- a/lib/icinga/service.cpp
+++ b/lib/icinga/service.cpp
@@ -103,32 +103,50 @@ Host::Ptr Service::GetHost() const
return m_Host;
}
-/* keep in sync with Host::GetSeverity() */
+/* keep in sync with Host::GetSeverity()
+ * One could think it may be smart to use an enum and some bitmask math here.
+ * But the only thing the consuming icingaweb2 cares about is being able to
+ * sort by severity. It is therefore easier to keep them seperated here. */
int Service::GetSeverity() const
{
- int severity = 0;
+ int severity;
ObjectLock olock(this);
ServiceState state = GetStateRaw();
- if (!HasBeenChecked())
- severity |= SeverityFlagPending;
- else if (state == ServiceWarning)
- severity |= SeverityFlagWarning;
- else if (state == ServiceUnknown)
- severity |= SeverityFlagUnknown;
- else if (state == ServiceCritical)
- severity |= SeverityFlagCritical;
+ if (!HasBeenChecked()) {
+ severity = 16;
+ } else if (state == ServiceOK) {
+ severity = 0;
+ } else {
+ switch (state) {
+ case ServiceWarning:
+ severity = 32;
+ break;
+ case ServiceUnknown:
+ severity = 64;
+ break;
+ case ServiceCritical:
+ severity = 128;
+ break;
+ default:
+ severity = 256;
+ }
- /* TODO: Add host reachability and handled */
- if (IsInDowntime())
- severity |= SeverityFlagDowntime;
- else if (IsAcknowledged())
- severity |= SeverityFlagAcknowledgement;
- else if (m_Host && m_Host->GetProblem())
- severity |= SeverityFlagHostDown;
- else
- severity |= SeverityFlagUnhandled;
+ Host::Ptr host = GetHost();
+ ObjectLock hlock (host);
+ if (host->GetState() != HostUp || !host->IsReachable()) {
+ severity += 1024;
+ } else {
+ if (IsAcknowledged())
+ severity += 512;
+ else if (IsInDowntime())
+ severity += 256;
+ else
+ severity += 2048;
+ }
+ hlock.Unlock();
+ }
olock.Unlock();
diff --git a/lib/icingadb/CMakeLists.txt b/lib/icingadb/CMakeLists.txt
new file mode 100644
index 000000000..71a7c67f2
--- /dev/null
+++ b/lib/icingadb/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+
+
+mkclass_target(icingadb.ti icingadb-ti.cpp icingadb-ti.hpp)
+
+set(icingadb_SOURCES
+ icingadb.cpp icingadb-objects.cpp icingadb-stats.cpp icingadb-utility.cpp redisconnection.cpp icingadb-ti.hpp
+)
+
+if(ICINGA2_UNITY_BUILD)
+ mkunity_target(icingadb icingadb icingadb_SOURCES)
+endif()
+
+add_library(icingadb OBJECT ${icingadb_SOURCES})
+
+include_directories(${icinga2_SOURCE_DIR}/third-party)
+
+add_dependencies(icingadb base config icinga remote)
+
+set_target_properties (
+ icingadb PROPERTIES
+ FOLDER Components
+)
+
+install_if_not_exists(
+ ${PROJECT_SOURCE_DIR}/etc/icinga2/features-available/icingadb.conf
+ ${CMAKE_INSTALL_SYSCONFDIR}/icinga2/features-available
+)
+
+set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}" PARENT_SCOPE)
diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp
new file mode 100644
index 000000000..0869aeb97
--- /dev/null
+++ b/lib/icingadb/icingadb-objects.cpp
@@ -0,0 +1,1783 @@
+/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
+
+#include "icingadb/icingadb.hpp"
+#include "icingadb/redisconnection.hpp"
+#include "base/configtype.hpp"
+#include "base/configobject.hpp"
+#include "base/json.hpp"
+#include "base/logger.hpp"
+#include "base/serializer.hpp"
+#include "base/tlsutility.hpp"
+#include "base/initialize.hpp"
+#include "base/convert.hpp"
+#include "base/array.hpp"
+#include "base/exception.hpp"
+#include "base/utility.hpp"
+#include "icinga/command.hpp"
+#include "icinga/compatutility.hpp"
+#include "icinga/customvarobject.hpp"
+#include "icinga/host.hpp"
+#include "icinga/service.hpp"
+#include "icinga/hostgroup.hpp"
+#include "icinga/servicegroup.hpp"
+#include "icinga/usergroup.hpp"
+#include "icinga/checkcommand.hpp"
+#include "icinga/eventcommand.hpp"
+#include "icinga/notificationcommand.hpp"
+#include "icinga/timeperiod.hpp"
+#include "icinga/pluginutility.hpp"
+#include "remote/zone.hpp"
+#include
+#include