2019-11-02 14:00:06 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2017-09-25 14:41:43 +02:00
2019-10-29 18:36:16 +01:00
# include "icingadb/icingadb.hpp"
# include "icingadb/icingadb-ti.cpp"
# include "icingadb/redisconnection.hpp"
2017-09-25 14:41:43 +02:00
# include "remote/eventqueue.hpp"
# include "base/json.hpp"
2018-10-30 16:00:41 +01:00
# include "icinga/checkable.hpp"
# include "icinga/host.hpp"
2017-10-12 17:46:06 +02:00
# include <boost/algorithm/string.hpp>
2019-11-02 18:01:31 +01:00
# include <memory>
2019-06-28 11:56:15 +02:00
# include <utility>
2017-09-25 14:41:43 +02:00
using namespace icinga ;
2017-10-12 17:46:06 +02:00
# define MAX_EVENTS_DEFAULT 5000
2017-10-11 14:19:42 +02:00
2019-11-27 11:08:22 +01:00
using Prio = RedisConnection : : QueryPriority ;
2021-03-19 15:31:19 +01:00
String IcingaDB : : m_EnvironmentId ;
boost : : once_flag IcingaDB : : m_EnvironmentIdOnce = BOOST_ONCE_INIT ;
2019-10-29 17:32:29 +01:00
REGISTER_TYPE ( IcingaDB ) ;
2017-09-25 14:41:43 +02:00
2019-10-29 17:32:29 +01:00
IcingaDB : : IcingaDB ( )
2019-11-02 18:01:31 +01:00
: m_Rcon ( nullptr )
2017-10-12 11:47:49 +02:00
{
2018-10-18 14:39:59 +02:00
m_Rcon = nullptr ;
2019-10-29 17:32:29 +01:00
m_WorkQueue . SetName ( " IcingaDB " ) ;
2018-07-10 11:09:37 +02:00
2021-04-22 08:56:28 +02:00
m_PrefixConfigObject = " icinga: " ;
2019-06-14 11:52:34 +02:00
m_PrefixConfigCheckSum = " icinga:checksum: " ;
2017-10-12 11:47:49 +02:00
}
2017-09-25 14:41:43 +02:00
2021-07-22 14:34:07 +02:00
void IcingaDB : : Validate ( int types , const ValidationUtils & utils )
{
ObjectImpl < IcingaDB > : : Validate ( types , utils ) ;
if ( ! ( types & FAConfig ) )
return ;
if ( GetEnableTls ( ) & & GetCertPath ( ) . IsEmpty ( ) ! = GetKeyPath ( ) . IsEmpty ( ) ) {
BOOST_THROW_EXCEPTION ( ValidationError ( this , std : : vector < String > ( ) , " Validation failed: Either both a client certificate (cert_path) and its private key (key_path) or none of them must be given. " ) ) ;
}
}
2017-09-25 14:41:43 +02:00
/**
* Starts the component .
*/
2019-10-29 17:32:29 +01:00
void IcingaDB : : Start ( bool runtimeCreated )
2017-09-25 14:41:43 +02:00
{
2019-10-29 17:32:29 +01:00
ObjectImpl < IcingaDB > : : Start ( runtimeCreated ) ;
2017-09-25 14:41:43 +02:00
2021-03-19 15:31:19 +01:00
boost : : call_once ( [ ] ( ) {
m_EnvironmentId = SHA1 ( GetEnvironment ( ) ) ;
} , m_EnvironmentIdOnce ) ;
2019-10-29 17:32:29 +01:00
Log ( LogInformation , " IcingaDB " )
2018-05-15 14:43:01 +02:00
< < " ' " < < GetName ( ) < < " ' started. " ;
2017-09-25 14:41:43 +02:00
m_ConfigDumpInProgress = false ;
2018-10-18 14:39:59 +02:00
m_ConfigDumpDone = false ;
2019-06-28 11:56:15 +02:00
m_WorkQueue . SetExceptionCallback ( [ this ] ( boost : : exception_ptr exp ) { ExceptionHandler ( std : : move ( exp ) ) ; } ) ;
2017-09-25 14:41:43 +02:00
2021-07-22 14:34:07 +02:00
m_Rcon = new RedisConnection ( GetHost ( ) , GetPort ( ) , GetPath ( ) , GetPassword ( ) , GetDbIndex ( ) ,
GetEnableTls ( ) , GetInsecureNoverify ( ) , GetCertPath ( ) , GetKeyPath ( ) , GetCaPath ( ) , GetCrlPath ( ) ,
2021-07-26 16:14:51 +02:00
GetTlsProtocolmin ( ) , GetCipherList ( ) , GetConnectTimeout ( ) , GetDebugInfo ( ) ) ;
2021-07-27 12:21:04 +02:00
auto connectedCallback ( [ this ] ( boost : : asio : : yield_context & yc ) {
2021-01-19 10:56:54 +01:00
m_WorkQueue . Enqueue ( [ this ] ( ) { OnConnectedHandler ( ) ; } ) ;
} ) ;
2021-07-27 12:21:04 +02:00
m_Rcon - > SetConnectedCallback ( [ this , connectedCallback ] ( boost : : asio : : yield_context & yc ) {
for ( auto & kv : m_Rcons ) {
kv . second - > Start ( ) ;
}
m_Rcon - > SetConnectedCallback ( connectedCallback ) ;
connectedCallback ( yc ) ;
} ) ;
2021-01-19 10:56:54 +01:00
m_Rcon - > Start ( ) ;
2017-09-25 14:41:43 +02:00
2021-03-23 12:37:32 +01:00
for ( const Type : : Ptr & type : GetTypes ( ) ) {
auto ctype ( dynamic_cast < ConfigType * > ( type . get ( ) ) ) ;
if ( ! ctype )
continue ;
2021-07-27 12:21:04 +02:00
m_Rcons [ ctype ] = new RedisConnection ( GetHost ( ) , GetPort ( ) , GetPath ( ) , GetPassword ( ) , GetDbIndex ( ) ,
2021-07-22 14:34:07 +02:00
GetEnableTls ( ) , GetInsecureNoverify ( ) , GetCertPath ( ) , GetKeyPath ( ) , GetCaPath ( ) , GetCrlPath ( ) ,
2021-07-26 16:14:51 +02:00
GetTlsProtocolmin ( ) , GetCipherList ( ) , GetConnectTimeout ( ) , GetDebugInfo ( ) , m_Rcon ) ;
2021-03-23 12:37:32 +01:00
}
2017-09-25 14:41:43 +02:00
m_StatsTimer = new Timer ( ) ;
2019-05-13 11:37:54 +02:00
m_StatsTimer - > SetInterval ( 1 ) ;
2019-06-28 11:56:15 +02:00
m_StatsTimer - > OnTimerExpired . connect ( [ this ] ( const Timer * const & ) { PublishStatsTimerHandler ( ) ; } ) ;
2017-09-25 14:41:43 +02:00
m_StatsTimer - > Start ( ) ;
2019-10-29 17:32:29 +01:00
m_WorkQueue . SetName ( " IcingaDB " ) ;
2017-10-02 09:59:11 +02:00
2019-12-17 16:41:34 +01:00
m_Rcon - > SuppressQueryKind ( Prio : : CheckResult ) ;
2021-07-26 16:39:18 +02:00
m_Rcon - > SuppressQueryKind ( Prio : : RuntimeStateSync ) ;
2017-09-25 14:41:43 +02:00
}
2019-10-29 17:32:29 +01:00
void IcingaDB : : ExceptionHandler ( boost : : exception_ptr exp )
2017-09-25 14:41:43 +02:00
{
2019-10-29 17:32:29 +01:00
Log ( LogCritical , " IcingaDB " , " Exception during redis query. Verify that Redis is operational. " ) ;
2017-09-25 14:41:43 +02:00
2019-10-29 17:32:29 +01:00
Log ( LogDebug , " IcingaDB " )
2018-05-15 14:43:01 +02:00
< < " Exception during redis operation: " < < DiagnosticInformation ( exp ) ;
2017-09-25 14:41:43 +02:00
}
2021-01-19 10:56:54 +01:00
void IcingaDB : : OnConnectedHandler ( )
2017-09-25 14:41:43 +02:00
{
AssertOnWorkQueue ( ) ;
2018-10-18 14:39:59 +02:00
if ( m_ConfigDumpInProgress | | m_ConfigDumpDone )
2017-09-25 14:41:43 +02:00
return ;
2017-10-12 11:47:49 +02:00
2017-09-25 14:41:43 +02:00
/* Config dump */
m_ConfigDumpInProgress = true ;
2019-01-28 15:19:10 +01:00
PublishStats ( ) ;
2017-09-25 14:41:43 +02:00
UpdateAllConfigObjects ( ) ;
2018-10-18 14:39:59 +02:00
m_ConfigDumpDone = true ;
2017-09-25 14:41:43 +02:00
m_ConfigDumpInProgress = false ;
}
2019-10-29 17:32:29 +01:00
void IcingaDB : : PublishStatsTimerHandler ( void )
2017-09-25 14:41:43 +02:00
{
2020-05-15 11:17:25 +02:00
PublishStats ( ) ;
2017-09-25 14:41:43 +02:00
}
2019-10-29 17:32:29 +01:00
void IcingaDB : : PublishStats ( )
2017-09-25 14:41:43 +02:00
{
2018-11-26 13:34:05 +01:00
if ( ! m_Rcon | | ! m_Rcon - > IsConnected ( ) )
2018-10-26 14:07:07 +02:00
return ;
2018-06-08 11:38:36 +02:00
Dictionary : : Ptr status = GetStats ( ) ;
2019-01-28 15:19:10 +01:00
status - > Set ( " config_dump_in_progress " , m_ConfigDumpInProgress ) ;
2019-12-05 10:32:15 +01:00
status - > Set ( " timestamp " , TimestampToMilliseconds ( Utility : : GetTime ( ) ) ) ;
2017-09-25 14:41:43 +02:00
2021-05-03 17:13:06 +02:00
std : : vector < String > query { " XADD " , " icinga:stats " , " MAXLEN " , " 1 " , " * " } ;
2019-12-02 18:06:07 +01:00
{
ObjectLock statusLock ( status ) ;
for ( auto & kv : status ) {
2021-05-03 17:13:06 +02:00
query . emplace_back ( kv . first ) ;
query . emplace_back ( JsonEncode ( kv . second ) ) ;
2019-12-02 18:06:07 +01:00
}
}
2021-05-03 17:13:06 +02:00
m_Rcon - > FireAndForgetQuery ( std : : move ( query ) , Prio : : Heartbeat ) ;
2017-09-25 14:41:43 +02:00
}
2019-10-29 17:32:29 +01:00
void IcingaDB : : Stop ( bool runtimeRemoved )
2017-09-25 14:41:43 +02:00
{
2019-10-29 17:32:29 +01:00
Log ( LogInformation , " IcingaDB " )
2018-05-15 14:43:01 +02:00
< < " ' " < < GetName ( ) < < " ' stopped. " ;
2017-09-25 14:41:43 +02:00
2019-10-29 17:32:29 +01:00
ObjectImpl < IcingaDB > : : Stop ( runtimeRemoved ) ;
2017-09-25 14:41:43 +02:00
}
2021-07-22 14:34:07 +02:00
void IcingaDB : : ValidateTlsProtocolmin ( const Lazy < String > & lvalue , const ValidationUtils & utils )
{
ObjectImpl < IcingaDB > : : ValidateTlsProtocolmin ( lvalue , utils ) ;
try {
ResolveTlsProtocolVersion ( lvalue ( ) ) ;
} catch ( const std : : exception & ex ) {
BOOST_THROW_EXCEPTION ( ValidationError ( this , { " tls_protocolmin " } , ex . what ( ) ) ) ;
}
}
2021-07-26 16:14:51 +02:00
void IcingaDB : : ValidateConnectTimeout ( const Lazy < double > & lvalue , const ValidationUtils & utils )
{
ObjectImpl < IcingaDB > : : ValidateConnectTimeout ( lvalue , utils ) ;
if ( lvalue ( ) < = 0 ) {
BOOST_THROW_EXCEPTION ( ValidationError ( this , { " connect_timeout " } , " Value must be greater than 0. " ) ) ;
}
}
2019-10-29 17:32:29 +01:00
void IcingaDB : : AssertOnWorkQueue ( )
2017-09-25 14:41:43 +02:00
{
ASSERT ( m_WorkQueue . IsWorkerThread ( ) ) ;
}
2021-02-24 13:37:36 +01:00
void IcingaDB : : DumpedGlobals : : Reset ( )
{
std : : lock_guard < std : : mutex > l ( m_Mutex ) ;
m_Ids . clear ( ) ;
}
bool IcingaDB : : DumpedGlobals : : IsNew ( const String & id )
{
std : : lock_guard < std : : mutex > l ( m_Mutex ) ;
return m_Ids . emplace ( id ) . second ;
}