2019-02-25 14:48:22 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2015-07-30 17:50:17 +02:00
# include "icinga/apiactions.hpp"
2020-09-21 18:41:15 +02:00
# include "icinga/checkable.hpp"
2015-07-30 17:50:17 +02:00
# include "icinga/service.hpp"
2015-08-03 15:27:09 +02:00
# include "icinga/servicegroup.hpp"
# include "icinga/hostgroup.hpp"
2015-07-31 17:18:49 +02:00
# include "icinga/pluginutility.hpp"
2015-08-03 15:27:09 +02:00
# include "icinga/checkcommand.hpp"
# include "icinga/eventcommand.hpp"
# include "icinga/notificationcommand.hpp"
2020-06-30 13:43:00 +02:00
# include "icinga/clusterevents.hpp"
2015-07-30 17:50:17 +02:00
# include "remote/apiaction.hpp"
2016-08-15 14:32:41 +02:00
# include "remote/apilistener.hpp"
2023-04-12 14:45:40 +02:00
# include "remote/configobjectslock.hpp"
2020-07-07 14:23:36 +02:00
# include "remote/filterutility.hpp"
2017-09-05 14:44:56 +02:00
# include "remote/pkiutility.hpp"
2015-07-30 17:50:17 +02:00
# include "remote/httputility.hpp"
# include "base/utility.hpp"
# include "base/convert.hpp"
2020-07-03 15:13:51 +02:00
# include "base/defer.hpp"
2020-07-03 10:16:23 +02:00
# include "remote/actionshandler.hpp"
2015-08-21 15:50:40 +02:00
# include <fstream>
2015-07-30 17:50:17 +02:00
using namespace icinga ;
2015-08-03 15:27:09 +02:00
REGISTER_APIACTION ( process_check_result , " Service;Host " , & ApiActions : : ProcessCheckResult ) ;
REGISTER_APIACTION ( reschedule_check , " Service;Host " , & ApiActions : : RescheduleCheck ) ;
2015-10-16 11:44:18 +02:00
REGISTER_APIACTION ( send_custom_notification , " Service;Host " , & ApiActions : : SendCustomNotification ) ;
REGISTER_APIACTION ( delay_notification , " Service;Host " , & ApiActions : : DelayNotification ) ;
2015-08-03 15:27:09 +02:00
REGISTER_APIACTION ( acknowledge_problem , " Service;Host " , & ApiActions : : AcknowledgeProblem ) ;
REGISTER_APIACTION ( remove_acknowledgement , " Service;Host " , & ApiActions : : RemoveAcknowledgement ) ;
REGISTER_APIACTION ( add_comment , " Service;Host " , & ApiActions : : AddComment ) ;
2015-11-08 12:41:47 +01:00
REGISTER_APIACTION ( remove_comment , " Service;Host;Comment " , & ApiActions : : RemoveComment ) ;
2015-08-21 12:47:49 +02:00
REGISTER_APIACTION ( schedule_downtime , " Service;Host " , & ApiActions : : ScheduleDowntime ) ;
2015-11-08 12:41:47 +01:00
REGISTER_APIACTION ( remove_downtime , " Service;Host;Downtime " , & ApiActions : : RemoveDowntime ) ;
2015-08-03 15:27:09 +02:00
REGISTER_APIACTION ( shutdown_process , " " , & ApiActions : : ShutdownProcess ) ;
REGISTER_APIACTION ( restart_process , " " , & ApiActions : : RestartProcess ) ;
2016-08-15 14:32:41 +02:00
REGISTER_APIACTION ( generate_ticket , " " , & ApiActions : : GenerateTicket ) ;
2020-06-02 11:43:32 +02:00
REGISTER_APIACTION ( execute_command , " Service;Host " , & ApiActions : : ExecuteCommand ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : CreateResult ( int code , const String & status ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & additional )
2015-08-03 15:27:09 +02:00
{
2018-01-11 11:17:38 +01:00
Dictionary : : Ptr result = new Dictionary ( {
{ " code " , code } ,
{ " status " , status }
} ) ;
2015-08-21 12:47:49 +02:00
if ( additional )
additional - > CopyTo ( result ) ;
2015-07-31 17:18:49 +02:00
return result ;
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : ProcessCheckResult ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-07-31 17:18:49 +02:00
{
2022-04-26 13:33:59 +02:00
using Result = Checkable : : ProcessingResult ;
2015-07-31 17:18:49 +02:00
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 ,
2017-12-19 15:50:05 +01:00
" Cannot process passive check result for non-existent object. " ) ;
2015-07-31 17:18:49 +02:00
if ( ! checkable - > GetEnablePassiveChecks ( ) )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 403 , " Passive checks are disabled for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-07-31 17:18:49 +02:00
2020-09-21 18:41:15 +02:00
if ( ! checkable - > IsReachable ( DependencyCheckExecution ) )
return ApiActions : : CreateResult ( 200 , " Ignoring passive check result for unreachable object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-07-31 17:18:49 +02:00
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( checkable ) ;
if ( ! params - > Contains ( " exit_status " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Parameter 'exit_status' is required. " ) ;
2015-07-31 17:18:49 +02:00
int exitStatus = HttpUtility : : GetLastParameter ( params , " exit_status " ) ;
ServiceState state ;
if ( ! service ) {
if ( exitStatus = = 0 )
state = ServiceOK ;
else if ( exitStatus = = 1 )
state = ServiceCritical ;
else
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Invalid 'exit_status' for Host "
2017-12-19 15:50:05 +01:00
+ checkable - > GetName ( ) + " . " ) ;
2015-07-31 17:18:49 +02:00
} else {
state = PluginUtility : : ExitStatusToState ( exitStatus ) ;
}
2015-08-03 15:27:09 +02:00
if ( ! params - > Contains ( " plugin_output " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Parameter 'plugin_output' is required " ) ;
2015-07-31 17:18:49 +02:00
CheckResult : : Ptr cr = new CheckResult ( ) ;
2015-08-03 15:27:09 +02:00
cr - > SetOutput ( HttpUtility : : GetLastParameter ( params , " plugin_output " ) ) ;
2015-07-31 17:18:49 +02:00
cr - > SetState ( state ) ;
2017-08-21 17:20:56 +02:00
if ( params - > Contains ( " execution_start " ) )
cr - > SetExecutionStart ( HttpUtility : : GetLastParameter ( params , " execution_start " ) ) ;
if ( params - > Contains ( " execution_end " ) )
cr - > SetExecutionEnd ( HttpUtility : : GetLastParameter ( params , " execution_end " ) ) ;
2015-07-31 17:18:49 +02:00
cr - > SetCheckSource ( HttpUtility : : GetLastParameter ( params , " check_source " ) ) ;
2021-07-20 11:10:26 +02:00
cr - > SetSchedulingSource ( HttpUtility : : GetLastParameter ( params , " scheduling_source " ) ) ;
2018-02-06 15:25:55 +01:00
Value perfData = params - > Get ( " performance_data " ) ;
/* Allow to pass a performance data string from Icinga Web 2 next to the new Array notation. */
if ( perfData . IsString ( ) )
cr - > SetPerformanceData ( PluginUtility : : SplitPerfdata ( perfData ) ) ;
else
cr - > SetPerformanceData ( perfData ) ;
2015-08-03 15:27:09 +02:00
cr - > SetCommand ( params - > Get ( " check_command " ) ) ;
2016-03-11 10:30:50 +01:00
/* Mark this check result as passive. */
cr - > SetActive ( false ) ;
2018-01-11 17:10:46 +01:00
/* Result TTL allows to overrule the next expected freshness check. */
if ( params - > Contains ( " ttl " ) )
cr - > SetTtl ( HttpUtility : : GetLastParameter ( params , " ttl " ) ) ;
2022-04-26 13:33:59 +02:00
Result result = checkable - > ProcessCheckResult ( cr ) ;
switch ( result ) {
case Result : : Ok :
return ApiActions : : CreateResult ( 200 , " Successfully processed check result for object ' " + checkable - > GetName ( ) + " '. " ) ;
case Result : : NoCheckResult :
return ApiActions : : CreateResult ( 400 , " Could not process check result for object ' " + checkable - > GetName ( ) + " ' because no check result was passed. " ) ;
case Result : : CheckableInactive :
return ApiActions : : CreateResult ( 503 , " Could not process check result for object ' " + checkable - > GetName ( ) + " ' because the object is inactive. " ) ;
case Result : : NewerCheckResultPresent :
return ApiActions : : CreateResult ( 409 , " Newer check result already present. Check result for ' " + checkable - > GetName ( ) + " ' was discarded. " ) ;
}
2015-07-31 17:18:49 +02:00
2022-04-26 13:33:59 +02:00
return ApiActions : : CreateResult ( 500 , " Unexpected result ( " + std : : to_string ( static_cast < int > ( result ) ) + " ) for object ' " + checkable - > GetName ( ) + " '. Please submit a bug report at https://github.com/Icinga/icinga2 " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : RescheduleCheck ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 , " Cannot reschedule check for non-existent object. " ) ;
if ( Convert : : ToBool ( HttpUtility : : GetLastParameter ( params , " force " ) ) )
checkable - > SetForceNextCheck ( true ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
double nextCheck ;
if ( params - > Contains ( " next_check " ) )
nextCheck = HttpUtility : : GetLastParameter ( params , " next_check " ) ;
else
nextCheck = Utility : : GetTime ( ) ;
checkable - > SetNextCheck ( nextCheck ) ;
2015-08-03 15:27:09 +02:00
2016-01-22 18:42:15 +01:00
/* trigger update event for DB IDO */
Checkable : : OnNextCheckUpdated ( checkable ) ;
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully rescheduled check for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : SendCustomNotification ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 , " Cannot send notification for non-existent object. " ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
if ( ! params - > Contains ( " author " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Parameter 'author' is required. " ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
if ( ! params - > Contains ( " comment " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Parameter 'comment' is required. " ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
if ( Convert : : ToBool ( HttpUtility : : GetLastParameter ( params , " force " ) ) )
checkable - > SetForceNextNotification ( true ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
Checkable : : OnNotificationsRequested ( checkable , NotificationCustom , checkable - > GetLastCheckResult ( ) ,
2017-12-19 15:50:05 +01:00
HttpUtility : : GetLastParameter ( params , " author " ) , HttpUtility : : GetLastParameter ( params , " comment " ) , nullptr ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully sent custom notification for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : DelayNotification ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
2015-08-21 12:47:49 +02:00
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
2015-08-03 15:27:09 +02:00
2015-08-21 12:47:49 +02:00
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 , " Cannot delay notifications for non-existent object " ) ;
if ( ! params - > Contains ( " timestamp " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " A timestamp is required to delay notifications " ) ;
2015-08-03 15:27:09 +02:00
2016-08-25 06:19:44 +02:00
for ( const Notification : : Ptr & notification : checkable - > GetNotifications ( ) ) {
2015-10-16 11:44:18 +02:00
notification - > SetNextNotification ( HttpUtility : : GetLastParameter ( params , " timestamp " ) ) ;
}
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully delayed notifications for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : AcknowledgeProblem ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-08-21 12:47:49 +02:00
return ApiActions : : CreateResult ( 404 , " Cannot acknowledge problem for non-existent object. " ) ;
2015-08-03 15:27:09 +02:00
if ( ! params - > Contains ( " author " ) | | ! params - > Contains ( " comment " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Acknowledgements require author and comment. " ) ;
2015-08-03 15:27:09 +02:00
AcknowledgementType sticky = AcknowledgementNormal ;
bool notify = false ;
2017-01-25 21:21:22 +01:00
bool persistent = false ;
2015-08-21 12:47:49 +02:00
double timestamp = 0.0 ;
2015-10-16 11:44:18 +02:00
2017-01-12 11:43:22 +01:00
if ( params - > Contains ( " sticky " ) & & HttpUtility : : GetLastParameter ( params , " sticky " ) )
2015-08-03 15:27:09 +02:00
sticky = AcknowledgementSticky ;
if ( params - > Contains ( " notify " ) )
2017-01-12 11:43:22 +01:00
notify = HttpUtility : : GetLastParameter ( params , " notify " ) ;
2017-01-25 21:21:22 +01:00
if ( params - > Contains ( " persistent " ) )
persistent = HttpUtility : : GetLastParameter ( params , " persistent " ) ;
2017-05-15 10:14:19 +02:00
if ( params - > Contains ( " expiry " ) ) {
2015-10-16 11:44:18 +02:00
timestamp = HttpUtility : : GetLastParameter ( params , " expiry " ) ;
2017-05-15 10:14:19 +02:00
if ( timestamp < = Utility : : GetTime ( ) )
return ApiActions : : CreateResult ( 409 , " Acknowledgement 'expiry' timestamp must be in the future for object " + checkable - > GetName ( ) ) ;
} else
2015-10-16 11:44:18 +02:00
timestamp = 0 ;
2015-08-03 15:27:09 +02:00
2019-12-05 11:08:16 +01:00
ObjectLock oLock ( checkable ) ;
2015-08-03 15:27:09 +02:00
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( checkable ) ;
2015-07-31 17:18:49 +02:00
if ( ! service ) {
2015-08-03 15:27:09 +02:00
if ( host - > GetState ( ) = = HostUp )
2015-08-21 12:47:49 +02:00
return ApiActions : : CreateResult ( 409 , " Host " + checkable - > GetName ( ) + " is UP. " ) ;
2015-08-03 15:27:09 +02:00
} else {
if ( service - > GetState ( ) = = ServiceOK )
2015-08-21 12:47:49 +02:00
return ApiActions : : CreateResult ( 409 , " Service " + checkable - > GetName ( ) + " is OK. " ) ;
2015-08-03 15:27:09 +02:00
}
2019-12-05 11:08:16 +01:00
if ( checkable - > IsAcknowledged ( ) ) {
return ApiActions : : CreateResult ( 409 , ( service ? " Service " : " Host " ) + checkable - > GetName ( ) + " is already acknowledged. " ) ;
}
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2015-08-20 17:18:48 +02:00
Comment : : AddComment ( checkable , CommentAcknowledgement , HttpUtility : : GetLastParameter ( params , " author " ) ,
2022-03-21 15:41:22 +01:00
HttpUtility : : GetLastParameter ( params , " comment " ) , persistent , timestamp , sticky = = AcknowledgementSticky ) ;
2015-08-03 15:27:09 +02:00
checkable - > AcknowledgeProblem ( HttpUtility : : GetLastParameter ( params , " author " ) ,
2019-12-04 15:19:03 +01:00
HttpUtility : : GetLastParameter ( params , " comment " ) , sticky , notify , persistent , Utility : : GetTime ( ) , timestamp ) ;
2015-08-21 12:47:49 +02:00
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully acknowledged problem for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : RemoveAcknowledgement ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 ,
2018-10-22 14:19:16 +02:00
" Cannot remove acknowledgement for non-existent checkable object "
2017-12-19 15:50:05 +01:00
+ object - > GetName ( ) + " . " ) ;
2015-08-03 15:27:09 +02:00
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2019-11-28 17:46:12 +01:00
String removedBy ( HttpUtility : : GetLastParameter ( params , " author " ) ) ;
checkable - > ClearAcknowledgement ( removedBy ) ;
2023-03-03 11:53:02 +01:00
checkable - > RemoveAckComments ( removedBy ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully removed acknowledgement for object ' " + checkable - > GetName ( ) + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : AddComment ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
return ApiActions : : CreateResult ( 404 , " Cannot add comment for non-existent object " ) ;
if ( ! params - > Contains ( " author " ) | | ! params - > Contains ( " comment " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Comments require author and comment. " ) ;
2015-08-03 15:27:09 +02:00
2020-05-27 11:41:22 +02:00
double timestamp = 0.0 ;
if ( params - > Contains ( " expiry " ) ) {
timestamp = HttpUtility : : GetLastParameter ( params , " expiry " ) ;
}
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2015-11-08 12:41:47 +01:00
String commentName = Comment : : AddComment ( checkable , CommentUser ,
2017-12-19 15:50:05 +01:00
HttpUtility : : GetLastParameter ( params , " author " ) ,
2020-05-27 11:41:22 +02:00
HttpUtility : : GetLastParameter ( params , " comment " ) , false , timestamp ) ;
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
Comment : : Ptr comment = Comment : : GetByName ( commentName ) ;
2015-08-21 12:47:49 +02:00
2018-01-11 11:17:38 +01:00
Dictionary : : Ptr additional = new Dictionary ( {
{ " name " , commentName } ,
{ " legacy_id " , comment - > GetLegacyId ( ) }
} ) ;
2015-08-21 12:47:49 +02:00
2015-11-06 16:45:09 +01:00
return ApiActions : : CreateResult ( 200 , " Successfully added comment ' "
2017-12-19 15:50:05 +01:00
+ commentName + " ' for object ' " + checkable - > GetName ( )
+ " '. " , additional ) ;
2015-08-03 15:27:09 +02:00
}
2015-11-08 12:41:47 +01:00
Dictionary : : Ptr ApiActions : : RemoveComment ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2019-11-21 15:53:40 +01:00
auto author ( HttpUtility : : GetLastParameter ( params , " author " ) ) ;
2015-11-08 12:41:47 +01:00
Checkable : : Ptr checkable = dynamic_pointer_cast < Checkable > ( object ) ;
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
if ( checkable ) {
std : : set < Comment : : Ptr > comments = checkable - > GetComments ( ) ;
2015-08-03 15:27:09 +02:00
2016-08-25 06:19:44 +02:00
for ( const Comment : : Ptr & comment : comments ) {
2021-12-13 16:37:45 +01:00
Comment : : RemoveComment ( comment - > GetName ( ) , true , author ) ;
2015-11-08 12:41:47 +01:00
}
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
return ApiActions : : CreateResult ( 200 , " Successfully removed all comments for object ' " + checkable - > GetName ( ) + " '. " ) ;
}
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
Comment : : Ptr comment = static_pointer_cast < Comment > ( object ) ;
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
if ( ! comment )
return ApiActions : : CreateResult ( 404 , " Cannot remove non-existent comment object. " ) ;
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
String commentName = comment - > GetName ( ) ;
2015-08-21 12:47:49 +02:00
2021-12-13 16:37:45 +01:00
Comment : : RemoveComment ( commentName , true , author ) ;
2015-11-01 16:33:43 +01:00
2015-11-08 12:41:47 +01:00
return ApiActions : : CreateResult ( 200 , " Successfully removed comment ' " + commentName + " '. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : ScheduleDowntime ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Checkable : : Ptr checkable = static_pointer_cast < Checkable > ( object ) ;
if ( ! checkable )
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 404 , " Can't schedule downtime for non-existent object. " ) ;
2015-08-03 15:27:09 +02:00
2015-10-16 11:44:18 +02:00
if ( ! params - > Contains ( " start_time " ) | | ! params - > Contains ( " end_time " ) | |
2017-12-19 15:50:05 +01:00
! params - > Contains ( " author " ) | | ! params - > Contains ( " comment " ) ) {
2015-08-03 15:27:09 +02:00
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Options 'start_time', 'end_time', 'author' and 'comment' are required " ) ;
2015-10-16 11:44:18 +02:00
}
2015-08-03 15:27:09 +02:00
2016-02-08 16:04:41 +01:00
bool fixed = true ;
2015-08-03 15:27:09 +02:00
if ( params - > Contains ( " fixed " ) )
2015-08-21 12:47:49 +02:00
fixed = HttpUtility : : GetLastParameter ( params , " fixed " ) ;
2015-08-03 15:27:09 +02:00
2016-08-16 17:08:41 +02:00
if ( ! fixed & & ! params - > Contains ( " duration " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Option 'duration' is required for flexible downtime " ) ;
2016-08-16 17:08:41 +02:00
2016-10-05 17:36:43 +02:00
double duration = 0.0 ;
if ( params - > Contains ( " duration " ) )
duration = HttpUtility : : GetLastParameter ( params , " duration " ) ;
2024-04-24 16:58:08 +02:00
Downtime : : Ptr trigger ;
String triggerName = HttpUtility : : GetLastParameter ( params , " trigger_name " ) ;
if ( ! triggerName . IsEmpty ( ) ) {
trigger = Downtime : : GetByName ( triggerName ) ;
if ( ! trigger ) {
return ApiActions : : CreateResult ( 404 , " Won't schedule downtime with non-existent trigger downtime. " ) ;
}
}
2016-10-05 17:36:43 +02:00
String author = HttpUtility : : GetLastParameter ( params , " author " ) ;
String comment = HttpUtility : : GetLastParameter ( params , " comment " ) ;
double startTime = HttpUtility : : GetLastParameter ( params , " start_time " ) ;
double endTime = HttpUtility : : GetLastParameter ( params , " end_time " ) ;
2019-06-03 16:01:10 +02:00
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( checkable ) ;
2018-10-24 11:00:24 +02:00
DowntimeChildOptions childOptions = DowntimeNoChildren ;
if ( params - > Contains ( " child_options " ) ) {
try {
childOptions = Downtime : : ChildOptionsFromValue ( HttpUtility : : GetLastParameter ( params , " child_options " ) ) ;
} catch ( const std : : exception & ) {
return ApiActions : : CreateResult ( 400 , " Option 'child_options' provided an invalid value. " ) ;
}
}
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2021-01-07 17:48:01 +01:00
Downtime : : Ptr downtime = Downtime : : AddDowntime ( checkable , author , comment , startTime , endTime ,
2024-04-24 16:58:08 +02:00
fixed , trigger , duration ) ;
2021-01-07 17:48:01 +01:00
String downtimeName = downtime - > GetName ( ) ;
2015-08-03 15:27:09 +02:00
2018-01-11 11:17:38 +01:00
Dictionary : : Ptr additional = new Dictionary ( {
{ " name " , downtimeName } ,
{ " legacy_id " , downtime - > GetLegacyId ( ) }
} ) ;
2015-08-21 12:47:49 +02:00
2019-06-04 10:04:54 +02:00
/* Schedule downtime for all services for the host type. */
bool allServices = false ;
if ( params - > Contains ( " all_services " ) )
allServices = HttpUtility : : GetLastParameter ( params , " all_services " ) ;
if ( allServices & & ! service ) {
ArrayData serviceDowntimes ;
for ( const Service : : Ptr & hostService : host - > GetServices ( ) ) {
Log ( LogNotice , " ApiActions " )
< < " Creating downtime for service " < < hostService - > GetName ( ) < < " on host " < < host - > GetName ( ) ;
2021-01-07 17:48:01 +01:00
Downtime : : Ptr serviceDowntime = Downtime : : AddDowntime ( hostService , author , comment , startTime , endTime ,
2024-04-24 16:58:08 +02:00
fixed , trigger , duration , String ( ) , String ( ) , downtimeName ) ;
2021-01-07 17:48:01 +01:00
String serviceDowntimeName = serviceDowntime - > GetName ( ) ;
2019-06-04 10:04:54 +02:00
serviceDowntimes . push_back ( new Dictionary ( {
{ " name " , serviceDowntimeName } ,
{ " legacy_id " , serviceDowntime - > GetLegacyId ( ) }
} ) ) ;
}
additional - > Set ( " service_downtimes " , new Array ( std : : move ( serviceDowntimes ) ) ) ;
}
2016-10-05 17:36:43 +02:00
/* Schedule downtime for all child objects. */
2018-08-08 14:42:18 +02:00
if ( childOptions ! = DowntimeNoChildren ) {
/* 'DowntimeTriggeredChildren' schedules child downtimes triggered by the parent downtime.
* ' DowntimeNonTriggeredChildren ' schedules non - triggered downtimes for all children .
2016-10-05 17:36:43 +02:00
*/
2024-04-24 16:58:08 +02:00
if ( childOptions = = DowntimeTriggeredChildren ) {
trigger = downtime ;
}
2016-10-05 17:36:43 +02:00
2018-08-08 14:42:18 +02:00
Log ( LogNotice , " ApiActions " )
2017-12-19 15:50:05 +01:00
< < " Processing child options " < < childOptions < < " for downtime " < < downtimeName ;
2016-10-05 17:36:43 +02:00
2018-01-11 11:17:38 +01:00
ArrayData childDowntimes ;
2021-09-03 12:05:34 +02:00
std : : set < Checkable : : Ptr > allChildren = checkable - > GetAllChildren ( ) ;
for ( const Checkable : : Ptr & child : allChildren ) {
Host : : Ptr childHost ;
Service : : Ptr childService ;
tie ( childHost , childService ) = GetHostService ( child ) ;
if ( allServices & & childService & &
allChildren . find ( static_pointer_cast < Checkable > ( childHost ) ) ! = allChildren . end ( ) ) {
/* When scheduling downtimes for all service and all children, the current child is a service, and its
* host is also a child , skip it here . The downtime for this service will be scheduled below together
* with the downtimes of all services for that host . Scheduling it below ensures that the relation
* from the child service downtime to the child host downtime is set properly . */
continue ;
}
2018-08-08 14:42:18 +02:00
Log ( LogNotice , " ApiActions " )
2017-12-19 15:50:05 +01:00
< < " Scheduling downtime for child object " < < child - > GetName ( ) ;
2016-10-05 17:36:43 +02:00
2021-01-07 17:48:01 +01:00
Downtime : : Ptr childDowntime = Downtime : : AddDowntime ( child , author , comment , startTime , endTime ,
2024-04-24 16:58:08 +02:00
fixed , trigger , duration ) ;
2021-01-07 17:48:01 +01:00
String childDowntimeName = childDowntime - > GetName ( ) ;
2016-10-05 17:36:43 +02:00
2018-08-08 14:42:18 +02:00
Log ( LogNotice , " ApiActions " )
2017-12-19 15:50:05 +01:00
< < " Add child downtime ' " < < childDowntimeName < < " '. " ;
2016-10-05 17:36:43 +02:00
2019-06-04 10:04:54 +02:00
Dictionary : : Ptr childAdditional = new Dictionary ( {
2018-01-11 11:17:38 +01:00
{ " name " , childDowntimeName } ,
{ " legacy_id " , childDowntime - > GetLegacyId ( ) }
2019-06-04 10:04:54 +02:00
} ) ;
2016-10-05 17:36:43 +02:00
2019-06-04 10:04:54 +02:00
/* For a host, also schedule all service downtimes if requested. */
if ( allServices & & ! childService ) {
ArrayData childServiceDowntimes ;
2019-06-03 16:01:10 +02:00
2021-09-02 16:18:55 +02:00
for ( const Service : : Ptr & childService : childHost - > GetServices ( ) ) {
2019-06-04 10:04:54 +02:00
Log ( LogNotice , " ApiActions " )
2021-09-02 16:18:55 +02:00
< < " Creating downtime for service " < < childService - > GetName ( ) < < " on child host " < < childHost - > GetName ( ) ;
2019-06-03 16:01:10 +02:00
2021-09-02 16:18:55 +02:00
Downtime : : Ptr serviceDowntime = Downtime : : AddDowntime ( childService , author , comment , startTime , endTime ,
2024-04-24 16:58:08 +02:00
fixed , trigger , duration , String ( ) , String ( ) , childDowntimeName ) ;
2021-01-07 17:48:01 +01:00
String serviceDowntimeName = serviceDowntime - > GetName ( ) ;
2019-06-03 16:01:10 +02:00
2019-06-04 10:04:54 +02:00
childServiceDowntimes . push_back ( new Dictionary ( {
{ " name " , serviceDowntimeName } ,
{ " legacy_id " , serviceDowntime - > GetLegacyId ( ) }
} ) ) ;
}
2019-06-03 16:01:10 +02:00
2019-06-04 10:04:54 +02:00
childAdditional - > Set ( " service_downtimes " , new Array ( std : : move ( childServiceDowntimes ) ) ) ;
}
2019-06-03 16:01:10 +02:00
2019-06-04 10:04:54 +02:00
childDowntimes . push_back ( childAdditional ) ;
2019-06-03 16:01:10 +02:00
}
2019-06-04 10:04:54 +02:00
additional - > Set ( " child_downtimes " , new Array ( std : : move ( childDowntimes ) ) ) ;
2019-06-03 16:01:10 +02:00
}
2015-11-06 16:45:09 +01:00
return ApiActions : : CreateResult ( 200 , " Successfully scheduled downtime ' " +
2017-12-19 15:50:05 +01:00
downtimeName + " ' for object ' " + checkable - > GetName ( ) + " '. " , additional ) ;
2015-08-03 15:27:09 +02:00
}
2015-11-08 12:41:47 +01:00
Dictionary : : Ptr ApiActions : : RemoveDowntime ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
2023-04-12 14:45:40 +02:00
ConfigObjectsSharedLock lock ( std : : try_to_lock ) ;
if ( ! lock ) {
return ApiActions : : CreateResult ( 503 , " Icinga is reloading. " ) ;
}
2019-11-21 15:28:25 +01:00
auto author ( HttpUtility : : GetLastParameter ( params , " author " ) ) ;
2015-11-08 12:41:47 +01:00
Checkable : : Ptr checkable = dynamic_pointer_cast < Checkable > ( object ) ;
2015-08-03 15:27:09 +02:00
2021-07-22 17:43:03 +02:00
size_t childCount = 0 ;
2015-11-08 12:41:47 +01:00
if ( checkable ) {
std : : set < Downtime : : Ptr > downtimes = checkable - > GetDowntimes ( ) ;
2015-08-21 15:50:40 +02:00
2016-08-25 06:19:44 +02:00
for ( const Downtime : : Ptr & downtime : downtimes ) {
2021-07-22 17:43:03 +02:00
childCount + = downtime - > GetChildren ( ) . size ( ) ;
2020-12-03 16:11:17 +01:00
try {
2024-05-16 11:55:43 +02:00
Downtime : : RemoveDowntime ( downtime - > GetName ( ) , true , DowntimeRemovedByUser , author ) ;
2020-12-03 16:11:17 +01:00
} catch ( const invalid_downtime_removal_error & error ) {
Log ( LogWarning , " ApiActions " ) < < error . what ( ) ;
return ApiActions : : CreateResult ( 400 , error . what ( ) ) ;
}
2015-11-08 12:41:47 +01:00
}
2015-08-21 15:50:40 +02:00
2021-07-22 17:43:03 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully removed all downtimes for object ' " +
checkable - > GetName ( ) + " ' and " + std : : to_string ( childCount ) + " child downtimes. " ) ;
2015-11-08 12:41:47 +01:00
}
2015-08-21 15:50:40 +02:00
2015-11-08 12:41:47 +01:00
Downtime : : Ptr downtime = static_pointer_cast < Downtime > ( object ) ;
2015-08-03 15:27:09 +02:00
2015-11-08 12:41:47 +01:00
if ( ! downtime )
return ApiActions : : CreateResult ( 404 , " Cannot remove non-existent downtime object. " ) ;
2015-08-03 15:27:09 +02:00
2021-07-22 17:43:03 +02:00
childCount + = downtime - > GetChildren ( ) . size ( ) ;
2020-12-03 16:11:17 +01:00
try {
String downtimeName = downtime - > GetName ( ) ;
2024-05-16 11:55:43 +02:00
Downtime : : RemoveDowntime ( downtimeName , true , DowntimeRemovedByUser , author ) ;
2015-08-03 15:27:09 +02:00
2021-07-22 17:43:03 +02:00
return ApiActions : : CreateResult ( 200 , " Successfully removed downtime ' " + downtimeName +
" ' and " + std : : to_string ( childCount ) + " child downtimes. " ) ;
2020-12-03 16:11:17 +01:00
} catch ( const invalid_downtime_removal_error & error ) {
Log ( LogWarning , " ApiActions " ) < < error . what ( ) ;
return ApiActions : : CreateResult ( 400 , error . what ( ) ) ;
}
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : ShutdownProcess ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Application : : RequestShutdown ( ) ;
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Shutting down Icinga 2. " ) ;
2015-08-03 15:27:09 +02:00
}
2015-10-16 11:44:18 +02:00
Dictionary : : Ptr ApiActions : : RestartProcess ( const ConfigObject : : Ptr & object ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2015-08-03 15:27:09 +02:00
{
Application : : RequestRestart ( ) ;
2015-10-16 11:44:18 +02:00
return ApiActions : : CreateResult ( 200 , " Restarting Icinga 2. " ) ;
2015-08-03 15:27:09 +02:00
}
2016-08-15 14:32:41 +02:00
Dictionary : : Ptr ApiActions : : GenerateTicket ( const ConfigObject : : Ptr & ,
2017-12-19 15:50:05 +01:00
const Dictionary : : Ptr & params )
2016-08-15 14:32:41 +02:00
{
if ( ! params - > Contains ( " cn " ) )
2017-11-03 13:29:24 +01:00
return ApiActions : : CreateResult ( 400 , " Option 'cn' is required " ) ;
2016-08-15 14:32:41 +02:00
String cn = HttpUtility : : GetLastParameter ( params , " cn " ) ;
ApiListener : : Ptr listener = ApiListener : : GetInstance ( ) ;
String salt = listener - > GetTicketSalt ( ) ;
if ( salt . IsEmpty ( ) )
return ApiActions : : CreateResult ( 500 , " Ticket salt is not configured in ApiListener object " ) ;
String ticket = PBKDF2_SHA1 ( cn , salt , 50000 ) ;
2018-01-11 11:17:38 +01:00
Dictionary : : Ptr additional = new Dictionary ( {
{ " ticket " , ticket }
} ) ;
2016-08-15 14:32:41 +02:00
return ApiActions : : CreateResult ( 200 , " Generated PKI ticket ' " + ticket + " ' for common name ' "
2017-12-19 15:50:05 +01:00
+ cn + " '. " , additional ) ;
2016-08-15 14:32:41 +02:00
}
2020-06-02 11:43:32 +02:00
2020-07-07 15:45:58 +02:00
Value ApiActions : : GetSingleObjectByNameUsingPermissions ( const String & type , const String & objectName , const ApiUser : : Ptr & user )
2020-07-07 14:23:36 +02:00
{
Dictionary : : Ptr queryParams = new Dictionary ( ) ;
queryParams - > Set ( " type " , type ) ;
2020-07-07 15:45:58 +02:00
queryParams - > Set ( type . ToLower ( ) , objectName ) ;
2020-07-07 14:23:36 +02:00
QueryDescription qd ;
qd . Types . insert ( type ) ;
qd . Permission = " objects/query/ " + type ;
std : : vector < Value > objs ;
2020-11-23 16:39:24 +01:00
2020-07-07 14:23:36 +02:00
try {
2020-07-07 15:45:58 +02:00
objs = FilterUtility : : GetFilterTargets ( qd , queryParams , user ) ;
2020-07-07 14:23:36 +02:00
} catch ( const std : : exception & ex ) {
2020-07-07 15:45:58 +02:00
Log ( LogWarning , " ApiActions " ) < < DiagnosticInformation ( ex ) ;
2020-07-07 14:23:36 +02:00
return nullptr ;
}
if ( objs . empty ( ) )
return nullptr ;
return objs . at ( 0 ) ;
} ;
2020-11-23 16:39:24 +01:00
Dictionary : : Ptr ApiActions : : ExecuteCommand ( const ConfigObject : : Ptr & object , const Dictionary : : Ptr & params )
2020-06-02 11:43:32 +02:00
{
2020-07-01 14:27:00 +02:00
ApiListener : : Ptr listener = ApiListener : : GetInstance ( ) ;
2020-11-23 16:39:24 +01:00
2020-07-01 14:27:00 +02:00
if ( ! listener )
BOOST_THROW_EXCEPTION ( std : : invalid_argument ( " No ApiListener instance configured. " ) ) ;
/* Get command_type */
2020-07-14 17:23:03 +02:00
String command_type = " EventCommand " ;
2020-11-23 16:39:24 +01:00
2020-07-01 14:27:00 +02:00
if ( params - > Contains ( " command_type " ) )
command_type = HttpUtility : : GetLastParameter ( params , " command_type " ) ;
/* Validate command_type */
2020-07-14 17:23:03 +02:00
if ( command_type ! = " EventCommand " & & command_type ! = " CheckCommand " & & command_type ! = " NotificationCommand " )
2020-07-01 14:27:00 +02:00
return ApiActions : : CreateResult ( 400 , " Invalid command_type ' " + command_type + " '. " ) ;
2020-06-30 15:41:47 +02:00
Checkable : : Ptr checkable = dynamic_pointer_cast < Checkable > ( object ) ;
2020-11-23 16:39:24 +01:00
2020-06-30 15:41:47 +02:00
if ( ! checkable )
2020-06-30 15:48:29 +02:00
return ApiActions : : CreateResult ( 404 , " Can't start a command execution for a non-existent object. " ) ;
2020-06-23 11:44:26 +02:00
2020-07-01 14:27:00 +02:00
/* Get TTL param */
if ( ! params - > Contains ( " ttl " ) )
return ApiActions : : CreateResult ( 400 , " Parameter ttl is required. " ) ;
double ttl = HttpUtility : : GetLastParameter ( params , " ttl " ) ;
2020-11-23 16:39:24 +01:00
2020-07-01 14:27:00 +02:00
if ( ttl < = 0 )
return ApiActions : : CreateResult ( 400 , " Parameter ttl must be greater than 0. " ) ;
2020-06-23 11:44:26 +02:00
ObjectLock oLock ( checkable ) ;
Host : : Ptr host ;
Service : : Ptr service ;
tie ( host , service ) = GetHostService ( checkable ) ;
String endpoint = " $command_endpoint$ " ;
2020-11-23 16:39:24 +01:00
2020-06-23 11:44:26 +02:00
if ( params - > Contains ( " endpoint " ) )
2020-06-30 15:51:15 +02:00
endpoint = HttpUtility : : GetLastParameter ( params , " endpoint " ) ;
2020-06-23 11:44:26 +02:00
MacroProcessor : : ResolverList resolvers ;
2020-07-31 11:15:17 +02:00
Value macros ;
2020-11-23 16:39:24 +01:00
2020-06-26 12:32:12 +02:00
if ( params - > Contains ( " macros " ) ) {
2020-07-31 11:15:17 +02:00
macros = HttpUtility : : GetLastParameter ( params , " macros " ) ;
2020-07-02 10:31:24 +02:00
if ( macros . IsObjectType < Dictionary > ( ) ) {
resolvers . emplace_back ( " override " , macros ) ;
2020-11-23 16:39:24 +01:00
} else {
2020-06-26 15:39:42 +02:00
return ApiActions : : CreateResult ( 400 , " Parameter macros must be a dictionary. " ) ;
2020-11-23 16:39:24 +01:00
}
2020-06-26 12:32:12 +02:00
}
2020-06-23 11:44:26 +02:00
if ( service )
resolvers . emplace_back ( " service " , service ) ;
2020-11-23 16:39:24 +01:00
2020-06-23 11:44:26 +02:00
resolvers . emplace_back ( " host " , host ) ;
String resolved_endpoint = MacroProcessor : : ResolveMacros (
endpoint , resolvers , checkable - > GetLastCheckResult ( ) ,
2020-06-26 14:29:03 +02:00
nullptr , MacroProcessor : : EscapeCallback ( ) , nullptr , false
2020-06-23 11:44:26 +02:00
) ;
2020-07-07 14:23:36 +02:00
if ( ! ActionsHandler : : AuthenticatedApiUser )
BOOST_THROW_EXCEPTION ( std : : invalid_argument ( " Can't find API user. " ) ) ;
/* Get endpoint */
2020-07-07 15:45:58 +02:00
Endpoint : : Ptr endpointPtr = GetSingleObjectByNameUsingPermissions ( Endpoint : : GetTypeName ( ) , resolved_endpoint , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-06-26 16:38:40 +02:00
if ( ! endpointPtr )
2020-06-23 11:44:26 +02:00
return ApiActions : : CreateResult ( 404 , " Can't find a valid endpoint for ' " + resolved_endpoint + " '. " ) ;
2023-04-12 17:30:04 +02:00
/* Return an error when
* the endpoint is different from the command endpoint of the checkable
* and the endpoint zone can ' t access the checkable .
* The endpoints are checked to allow for the case where command_endpoint is specified in the checkable
* but checkable is not actually present in the agent .
*/
2021-07-30 10:17:43 +02:00
Zone : : Ptr endpointZone = endpointPtr - > GetZone ( ) ;
2023-04-12 17:30:04 +02:00
Endpoint : : Ptr commandEndpoint = checkable - > GetCommandEndpoint ( ) ;
if ( endpointPtr ! = commandEndpoint & & ! endpointZone - > CanAccessObject ( checkable ) ) {
2021-07-30 10:17:43 +02:00
return ApiActions : : CreateResult (
409 ,
" Zone ' " + endpointZone - > GetName ( ) + " ' cannot access checkable ' " + checkable - > GetName ( ) + " '. "
) ;
}
2020-06-23 11:44:26 +02:00
/* Get command */
String command ;
2020-11-23 16:39:24 +01:00
2020-06-23 11:44:26 +02:00
if ( ! params - > Contains ( " command " ) ) {
2020-07-14 17:23:03 +02:00
if ( command_type = = " CheckCommand " ) {
2020-06-23 11:44:26 +02:00
command = " $check_command$ " ;
2020-07-14 17:23:03 +02:00
} else if ( command_type = = " EventCommand " ) {
2020-06-23 11:44:26 +02:00
command = " $event_command$ " ;
2020-07-14 12:01:12 +02:00
} else if ( command_type = = " NotificationCommand " ) {
2020-06-23 11:44:26 +02:00
command = " $notification_command$ " ;
}
} else {
command = HttpUtility : : GetLastParameter ( params , " command " ) ;
}
/* Resolve command macro */
String resolved_command = MacroProcessor : : ResolveMacros (
2020-06-26 12:32:12 +02:00
command , resolvers , checkable - > GetLastCheckResult ( ) , nullptr ,
MacroProcessor : : EscapeCallback ( ) , nullptr , false
2020-06-23 11:44:26 +02:00
) ;
2020-07-03 08:43:50 +02:00
CheckResult : : Ptr cr = checkable - > GetLastCheckResult ( ) ;
2020-11-23 16:39:24 +01:00
2020-07-31 08:53:10 +02:00
if ( ! cr )
cr = new CheckResult ( ) ;
2020-07-02 12:20:16 +02:00
2020-06-23 11:44:26 +02:00
/* Check if resolved_command exists and it is of type command_type */
2020-07-02 12:20:16 +02:00
Dictionary : : Ptr execMacros = new Dictionary ( ) ;
2020-07-03 15:13:51 +02:00
2020-07-31 11:15:17 +02:00
MacroResolver : : OverrideMacros = macros ;
2020-07-03 15:13:51 +02:00
Defer o ( [ ] ( ) {
2020-07-03 15:53:51 +02:00
MacroResolver : : OverrideMacros = nullptr ;
2020-07-03 15:13:51 +02:00
} ) ;
2020-07-21 13:27:03 +02:00
/* Create execution parameters */
Dictionary : : Ptr execParams = new Dictionary ( ) ;
2020-07-14 17:23:03 +02:00
if ( command_type = = " CheckCommand " ) {
2020-07-07 15:45:58 +02:00
CheckCommand : : Ptr cmd = GetSingleObjectByNameUsingPermissions ( CheckCommand : : GetTypeName ( ) , resolved_command , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( ! cmd )
2020-07-01 08:19:35 +02:00
return ApiActions : : CreateResult ( 404 , " Can't find a valid " + command_type + " for ' " + resolved_command + " '. " ) ;
2020-07-31 17:28:33 +02:00
else {
CheckCommand : : ExecuteOverride = cmd ;
Defer resetCheckCommandOverride ( [ ] ( ) {
CheckCommand : : ExecuteOverride = nullptr ;
} ) ;
2020-07-02 12:20:16 +02:00
cmd - > Execute ( checkable , cr , execMacros , false ) ;
2020-07-31 17:28:33 +02:00
}
2020-07-14 17:23:03 +02:00
} else if ( command_type = = " EventCommand " ) {
2020-07-07 15:45:58 +02:00
EventCommand : : Ptr cmd = GetSingleObjectByNameUsingPermissions ( EventCommand : : GetTypeName ( ) , resolved_command , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( ! cmd )
2020-07-01 08:19:35 +02:00
return ApiActions : : CreateResult ( 404 , " Can't find a valid " + command_type + " for ' " + resolved_command + " '. " ) ;
2020-07-31 17:28:33 +02:00
else {
EventCommand : : ExecuteOverride = cmd ;
2020-11-23 16:43:47 +01:00
Defer resetEventCommandOverride ( [ ] ( ) {
2020-07-31 17:28:33 +02:00
EventCommand : : ExecuteOverride = nullptr ;
} ) ;
2020-07-02 12:20:16 +02:00
cmd - > Execute ( checkable , execMacros , false ) ;
2020-07-31 17:28:33 +02:00
}
2020-07-14 12:01:12 +02:00
} else if ( command_type = = " NotificationCommand " ) {
2020-07-07 15:45:58 +02:00
NotificationCommand : : Ptr cmd = GetSingleObjectByNameUsingPermissions ( NotificationCommand : : GetTypeName ( ) , resolved_command , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( ! cmd )
2020-07-01 08:19:35 +02:00
return ApiActions : : CreateResult ( 404 , " Can't find a valid " + command_type + " for ' " + resolved_command + " '. " ) ;
2020-07-02 12:20:16 +02:00
else {
/* Get user */
String user_string = " " ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( params - > Contains ( " user " ) )
user_string = HttpUtility : : GetLastParameter ( params , " user " ) ;
/* Resolve user macro */
String resolved_user = MacroProcessor : : ResolveMacros (
2020-07-03 08:38:39 +02:00
user_string , resolvers , checkable - > GetLastCheckResult ( ) , nullptr ,
MacroProcessor : : EscapeCallback ( ) , nullptr , false
2020-07-02 12:20:16 +02:00
) ;
2020-07-07 15:45:58 +02:00
User : : Ptr user = GetSingleObjectByNameUsingPermissions ( User : : GetTypeName ( ) , resolved_user , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( ! user )
return ApiActions : : CreateResult ( 404 , " Can't find a valid user for ' " + resolved_user + " '. " ) ;
2020-11-23 16:39:24 +01:00
2020-07-21 13:27:03 +02:00
execParams - > Set ( " user " , user - > GetName ( ) ) ;
2020-07-02 12:20:16 +02:00
/* Get notification */
String notification_string = " " ;
2020-11-23 16:39:24 +01:00
2020-07-02 12:20:16 +02:00
if ( params - > Contains ( " notification " ) )
notification_string = HttpUtility : : GetLastParameter ( params , " notification " ) ;
/* Resolve notification macro */
String resolved_notification = MacroProcessor : : ResolveMacros (
2020-07-03 08:38:39 +02:00
notification_string , resolvers , checkable - > GetLastCheckResult ( ) , nullptr ,
MacroProcessor : : EscapeCallback ( ) , nullptr , false
2020-07-02 12:20:16 +02:00
) ;
2020-07-07 15:45:58 +02:00
Notification : : Ptr notification = GetSingleObjectByNameUsingPermissions ( Notification : : GetTypeName ( ) , resolved_notification , ActionsHandler : : AuthenticatedApiUser ) ;
2020-11-23 16:39:24 +01:00
2020-07-07 14:23:36 +02:00
if ( ! notification )
2020-07-02 12:20:16 +02:00
return ApiActions : : CreateResult ( 404 , " Can't find a valid notification for ' " + resolved_notification + " '. " ) ;
2020-11-23 16:39:24 +01:00
2020-07-21 13:27:03 +02:00
execParams - > Set ( " notification " , notification - > GetName ( ) ) ;
2020-07-02 12:20:16 +02:00
2020-07-31 17:28:33 +02:00
NotificationCommand : : ExecuteOverride = cmd ;
2020-11-23 16:43:47 +01:00
Defer resetNotificationCommandOverride ( [ ] ( ) {
2020-07-31 17:28:33 +02:00
NotificationCommand : : ExecuteOverride = nullptr ;
} ) ;
2020-07-03 11:00:40 +02:00
cmd - > Execute ( notification , user , cr , NotificationType : : NotificationCustom ,
2020-07-03 11:17:36 +02:00
ActionsHandler : : AuthenticatedApiUser - > GetName ( ) , " " , execMacros , false ) ;
2020-07-02 12:20:16 +02:00
}
2020-06-26 09:33:23 +02:00
}
2020-06-23 11:44:26 +02:00
/* This generates a UUID */
String uuid = Utility : : NewUniqueID ( ) ;
/* Create the deadline */
double deadline = Utility : : GetTime ( ) + ttl ;
/* Update executions */
Dictionary : : Ptr pending_execution = new Dictionary ( ) ;
pending_execution - > Set ( " pending " , true ) ;
pending_execution - > Set ( " deadline " , deadline ) ;
2021-07-30 10:17:43 +02:00
pending_execution - > Set ( " endpoint " , resolved_endpoint ) ;
2020-06-23 11:44:26 +02:00
Dictionary : : Ptr executions = checkable - > GetExecutions ( ) ;
2020-11-23 16:39:24 +01:00
2020-06-23 11:44:26 +02:00
if ( ! executions )
executions = new Dictionary ( ) ;
2020-11-23 16:39:24 +01:00
2020-06-23 11:44:26 +02:00
executions - > Set ( uuid , pending_execution ) ;
checkable - > SetExecutions ( executions ) ;
2020-06-30 17:50:08 +02:00
/* Broadcast the update */
2020-07-01 14:27:00 +02:00
Dictionary : : Ptr executionsToBroadcast = new Dictionary ( ) ;
executionsToBroadcast - > Set ( uuid , pending_execution ) ;
2020-06-30 17:50:08 +02:00
Dictionary : : Ptr updateParams = new Dictionary ( ) ;
updateParams - > Set ( " host " , host - > GetName ( ) ) ;
2020-11-23 16:39:24 +01:00
2020-06-30 17:50:08 +02:00
if ( service )
updateParams - > Set ( " service " , service - > GetShortName ( ) ) ;
2020-11-23 16:39:24 +01:00
2020-07-01 14:27:00 +02:00
updateParams - > Set ( " executions " , executionsToBroadcast ) ;
2020-06-30 17:50:08 +02:00
Dictionary : : Ptr updateMessage = new Dictionary ( ) ;
updateMessage - > Set ( " jsonrpc " , " 2.0 " ) ;
updateMessage - > Set ( " method " , " event::UpdateExecutions " ) ;
updateMessage - > Set ( " params " , updateParams ) ;
MessageOrigin : : Ptr origin = new MessageOrigin ( ) ;
listener - > RelayMessage ( origin , checkable , updateMessage , true ) ;
2020-07-21 13:27:03 +02:00
/* Populate execution parameters */
2020-07-14 17:23:03 +02:00
if ( command_type = = " CheckCommand " )
execParams - > Set ( " command_type " , " check_command " ) ;
else if ( command_type = = " EventCommand " )
execParams - > Set ( " command_type " , " event_command " ) ;
else if ( command_type = = " NotificationCommand " )
execParams - > Set ( " command_type " , " notification_command " ) ;
2020-11-23 16:39:24 +01:00
2020-06-30 13:43:00 +02:00
execParams - > Set ( " command " , resolved_command ) ;
execParams - > Set ( " host " , host - > GetName ( ) ) ;
2020-11-23 16:39:24 +01:00
2020-06-30 13:43:00 +02:00
if ( service )
execParams - > Set ( " service " , service - > GetShortName ( ) ) ;
/*
* If the host / service object specifies the ' check_timeout ' attribute ,
* forward this to the remote endpoint to limit the command execution time .
*/
if ( ! checkable - > GetCheckTimeout ( ) . IsEmpty ( ) )
execParams - > Set ( " check_timeout " , checkable - > GetCheckTimeout ( ) ) ;
execParams - > Set ( " source " , uuid ) ;
execParams - > Set ( " deadline " , deadline ) ;
2020-07-02 10:31:24 +02:00
execParams - > Set ( " macros " , execMacros ) ;
2020-08-03 21:09:57 +02:00
execParams - > Set ( " endpoint " , resolved_endpoint ) ;
2020-06-30 13:43:00 +02:00
2020-06-30 17:50:08 +02:00
/* Execute command */
2020-06-26 16:38:40 +02:00
bool local = endpointPtr = = Endpoint : : GetLocalEndpoint ( ) ;
2020-11-23 16:39:24 +01:00
2020-06-26 12:32:12 +02:00
if ( local ) {
2020-06-30 13:43:00 +02:00
ClusterEvents : : ExecuteCommandAPIHandler ( origin , execParams ) ;
2020-06-26 12:32:12 +02:00
} else {
2020-08-05 10:01:29 +02:00
/* Check if the child endpoints have Icinga version >= 2.13 */
Zone : : Ptr localZone = Zone : : GetLocalZone ( ) ;
for ( const Zone : : Ptr & zone : ConfigType : : GetObjectsByType < Zone > ( ) ) {
/* Fetch immediate child zone members */
2020-08-05 14:08:54 +02:00
if ( zone - > GetParent ( ) = = localZone & & zone - > CanAccessObject ( endpointPtr - > GetZone ( ) ) ) {
2020-08-05 10:01:29 +02:00
std : : set < Endpoint : : Ptr > endpoints = zone - > GetEndpoints ( ) ;
for ( const Endpoint : : Ptr & childEndpoint : endpoints ) {
2020-10-19 12:31:57 +02:00
if ( ! ( childEndpoint - > GetCapabilities ( ) & ( uint_fast64_t ) ApiCapabilities : : ExecuteArbitraryCommand ) ) {
2020-08-05 14:08:54 +02:00
/* Update execution */
double now = Utility : : GetTime ( ) ;
2020-08-05 15:53:34 +02:00
pending_execution - > Set ( " exit " , 126 ) ;
2020-10-19 12:31:57 +02:00
pending_execution - > Set ( " output " , " Endpoint ' " + childEndpoint - > GetName ( ) + " ' doesn't support executing arbitrary commands. " ) ;
2020-08-05 14:08:54 +02:00
pending_execution - > Set ( " start " , now ) ;
pending_execution - > Set ( " end " , now ) ;
pending_execution - > Remove ( " pending " ) ;
listener - > RelayMessage ( origin , checkable , updateMessage , true ) ;
Dictionary : : Ptr result = new Dictionary ( ) ;
result - > Set ( " checkable " , checkable - > GetName ( ) ) ;
result - > Set ( " execution " , uuid ) ;
return ApiActions : : CreateResult ( 202 , " Accepted " , result ) ;
2020-08-05 10:01:29 +02:00
}
}
}
}
2020-06-26 12:32:12 +02:00
Dictionary : : Ptr execMessage = new Dictionary ( ) ;
execMessage - > Set ( " jsonrpc " , " 2.0 " ) ;
execMessage - > Set ( " method " , " event::ExecuteCommand " ) ;
execMessage - > Set ( " params " , execParams ) ;
2020-06-23 11:44:26 +02:00
2020-08-04 14:32:36 +02:00
listener - > RelayMessage ( origin , endpointPtr - > GetZone ( ) , execMessage , true ) ;
2020-06-26 12:32:12 +02:00
}
2020-06-23 11:44:26 +02:00
Dictionary : : Ptr result = new Dictionary ( ) ;
2020-07-06 17:30:18 +02:00
result - > Set ( " checkable " , checkable - > GetName ( ) ) ;
result - > Set ( " execution " , uuid ) ;
2020-06-16 14:18:11 +02:00
return ApiActions : : CreateResult ( 202 , " Accepted " , result ) ;
2020-06-26 16:36:57 +02:00
}