2021-06-14 13:56:42 +02:00
#!/usr/bin/perl
###############################################################################
2021-08-25 11:47:30 +02:00
# Pandora FMS Daemon Watchdog
2021-06-14 13:56:42 +02:00
###############################################################################
2023-07-03 17:20:25 +02:00
# Copyright (c) 2018-2023 Pandora FMS
2021-06-14 13:56:42 +02:00
###############################################################################
use strict ;
use warnings ;
use DBI ;
use Getopt::Std ;
use POSIX qw( setsid strftime :sys_wait_h ) ;
use threads ;
use threads::shared ;
use File::Path qw( rmtree ) ;
# Default lib dir for Pandora FMS RPM and DEB packages.
2022-03-08 12:10:39 +01:00
BEGIN { push @ INC , '/usr/lib/perl5' ; }
2021-06-14 13:56:42 +02:00
use PandoraFMS::Tools ;
use PandoraFMS::DB ;
use PandoraFMS::Core ;
use PandoraFMS::Config ;
use Data::Dumper ;
$ Data:: Dumper:: Sortkeys = 1 ;
# Pandora server configuration.
my % Conf ;
# Command line options.
my % Opts ;
# Run as a daemon.
my $ DAEMON = 0 ;
2023-03-15 12:48:47 +01:00
# Timeout for the HA DB lock.
my $ LOCK_TIMEOUT = 300 ;
2021-06-14 13:56:42 +02:00
# Avoid retry old processing orders.
my $ First_Cleanup = 1 ;
2023-03-15 12:48:47 +01:00
# List of known HA DB hosts.
my @ HA_DB_Hosts ;
# Current master node.
my $ DB_Host = '' ;
2021-06-14 13:56:42 +02:00
# PID file.
my $ PID_FILE = '/var/run/pandora_ha.pid' ;
# Server service handler.
my $ Pandora_Service ;
2023-03-15 12:48:47 +01:00
# Restart the Pandora FMS Server.
my $ Restart = 0 ;
2021-06-14 13:56:42 +02:00
# Controlled exit
my $ Running = 0 ;
2024-02-12 14:58:00 +01:00
# License
my $ License ;
2021-06-14 13:56:42 +02:00
########################################################################
# Print the given message with a preceding timestamp.
########################################################################
2021-09-21 12:48:57 +02:00
sub log_message ($$$;$) {
my ( $ conf , $ source , $ message , $ verbosity_level ) = @ _ ;
my $ level = $ verbosity_level ;
$ level = 5 unless defined ( $ level ) ;
2021-06-14 13:56:42 +02:00
2023-03-15 12:48:47 +01:00
if ( $ source eq 'DEBUG' && ! defined ( $ ENV { 'PANDORA_DEBUG' } ) ) {
return ;
}
2021-06-14 13:56:42 +02:00
if ( ref ( $ conf ) eq "HASH" ) {
2021-09-21 12:48:57 +02:00
logger ( $ conf , 'HA (' . $ source . ') ' . "$message" , $ level ) ;
2021-06-14 13:56:42 +02:00
}
if ( $ source eq '' ) {
print $ message ;
}
else {
print strftime ( "%H:%M:%S" , localtime ( ) ) . ' [' . $ source . '] ' . "$message\n" ;
}
}
########################################################################
# Run as a daemon in the background.
########################################################################
sub ha_daemonize ($) {
my ( $ pa_config ) = @ _ ;
$ PID_FILE = $ pa_config - > { 'ha_pid_file' } if defined ( $ pa_config - > { 'ha_pid_file' } ) ;
open STDIN , "$DEVNULL" or die "Can't read $DEVNULL: $!" ;
open STDOUT , ">>$DEVNULL" or die "Can't write to $DEVNULL: $!" ;
open STDERR , ">>$DEVNULL" or die "Can't write to $DEVNULL: $!" ;
chdir '/tmp' or die "Can't chdir to /tmp: $!" ;
# Fork!
defined ( my $ pid = fork ) or die "Can't fork: $!" ;
2022-03-09 13:46:40 +01:00
exit if ( $ pid ) ;
# Child inherits execution.
setsid or die "Can't start a new session: $!" ;
# Store PID of this process in file presented by config token
if ( $ PID_FILE ne "" ) {
if ( - e $ PID_FILE && open ( FILE , $ PID_FILE ) ) {
$ pid = <FILE> + 0 ;
close FILE ;
# Check if pandora_ha is running.
die "[ERROR] pandora_ha is already running with pid: $pid.\n" if ( kill ( 0 , $ pid ) ) ;
2021-06-14 13:56:42 +02:00
}
2022-03-09 13:46:40 +01:00
umask 0022 ;
open ( FILE , '>' , $ PID_FILE ) or die "[FATAL] $!" ;
print FILE $$ ;
close ( FILE ) ;
2021-06-14 13:56:42 +02:00
}
}
########################################################################
# Check command line parameters.
########################################################################
sub ha_init_pandora ($) {
my $ conf = shift ;
2023-06-23 23:37:27 +02:00
log_message ( $ conf , '' , "\nPandora FMS Daemon Watchdog " . $ PandoraFMS:: Tools:: VERSION . " Copyright (c) Pandora FMS\n" ) ;
2021-06-14 13:56:42 +02:00
getopts ( 'dp:' , \ % Opts ) ;
# Run as a daemon.
$ DAEMON = 1 if ( defined ( $ Opts { 'd' } ) ) ;
# PID file.
$ PID_FILE = $ Opts { 'p' } if ( defined ( $ Opts { 'p' } ) ) ;
# Load config file from command line.
help_screen ( ) if ( $# ARGV != 0 ) ;
$ conf - > { '_pandora_path' } = $ ARGV [ 0 ] ;
}
########################################################################
# Read external configuration file.
########################################################################
sub ha_load_pandora_conf ($) {
my $ conf = shift ;
# Set some defaults.
$ conf - > { "servername" } = `hostname` ;
chomp ( $ conf - > { "servername" } ) ;
$ conf - > { "ha_file" } = '/etc/pandora/pandora_ha.bin' unless defined $ conf - > { "ha_file" } ;
pandora_init ( $ conf , 'Pandora HA' ) ;
pandora_load_config ( $ conf ) ;
# Check conf tokens.
foreach my $ param ( 'dbuser' , 'dbpass' , 'dbname' , 'dbhost' , 'log_file' ) {
die ( "[ERROR] Bad config values. Make sure " . $ conf - > { '_pandora_path' } . " is a valid config file.\n\n" ) unless defined ( $ conf - > { $ param } ) ;
}
$ conf - > { 'dbengine' } = 'mysql' unless defined ( $ conf - > { 'dbengine' } ) ;
$ conf - > { 'dbport' } = '3306' unless defined ( $ conf - > { 'dbport' } ) ;
$ conf - > { 'ha_interval' } = 10 unless defined ( $ conf - > { 'ha_interval' } ) ;
$ conf - > { 'ha_monitoring_interval' } = 60 unless defined ( $ conf - > { 'ha_monitoring_interval' } ) ;
2022-04-13 13:14:54 +02:00
$ conf - > { 'pandora_service_cmd' } = 'service pandora_server' unless defined ( $ conf - > { 'pandora_service_cmd' } ) ;
$ conf - > { 'tentacle_service_cmd' } = 'service tentacle_serverd' unless defined ( $ conf - > { 'tentacle_service_cmd' } ) ;
$ conf - > { 'tentacle_service_watchdog' } = 1 unless defined ( $ conf - > { 'tentacle_service_watchdog' } ) ;
2023-10-10 11:04:25 +02:00
$ conf - > { 'made_service_cmd' } = 'service pandora_made' unless defined ( $ conf - > { 'made_service_cmd' } ) ;
2021-06-14 13:56:42 +02:00
}
##############################################################################
# Print a help screen and exit.
##############################################################################
sub help_screen {
log_message ( undef , '' , "Usage: $0 [options] <path to pandora_server.conf>\n\nOptions:\n\t-p <PID file> Write the PID of the process to the specified file.\n\t-d Run in the background.\n\n" ) ;
exit 1 ;
}
##############################################################################
# Keep server running
##############################################################################
sub ha_keep_pandora_running ($$) {
my ( $ conf , $ dbh ) = @ _ ;
2021-07-19 06:47:24 +02:00
my $ OSNAME = $^O ;
my $ control_command ;
2023-03-15 12:48:47 +01:00
$ Pandora_Service = $ conf - > { 'pandora_service_cmd' } ;
# A restart was requested.
if ( $ Restart == 1 ) {
$ Restart = 0 ;
log_message ( $ conf , 'LOG' , 'Restarting Pandora service' ) ;
$ control_command = $^O eq "freebsd" ? "restart_server" : 'restart-server' ;
`$Pandora_Service $control_command $ENV{'PANDORA_DBHOST'} 2>/dev/null` ;
return ;
}
2021-06-14 13:56:42 +02:00
# Check if all servers are running
# Restart if crashed or keep interval is over.
my $ component_last_contact = get_db_value (
$ dbh ,
' SELECT count ( * ) AS "delayed"
FROM tserver
WHERE ( ( status = - 1 ) OR ( ( unix_timestamp ( ) - unix_timestamp ( keepalive ) ) > ( server_keepalive + 1 ) AND status != 0 ) )
2021-07-28 15:06:00 +02:00
AND server_type NOT IN ( ? , ? ) AND name = ? ' ,
2021-06-14 13:56:42 +02:00
PandoraFMS::Tools:: SATELLITESERVER ,
2021-07-28 15:06:00 +02:00
PandoraFMS::Tools:: MFSERVER ,
2021-06-14 13:56:42 +02:00
$ conf - > { 'servername' }
) ;
my $ nservers = get_db_value ( $ dbh , 'SELECT count(*) FROM tserver where name = ?' , $ conf - > { 'servername' } ) ;
# Check if service is running
2021-07-21 02:08:01 +02:00
$ control_command = "status-server" ;
2021-07-19 06:47:24 +02:00
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "status_server" ;
}
2023-03-08 11:46:03 +01:00
my $ pid = `$Pandora_Service $control_command | grep -v /conf.d/ | awk '{print \$NF*1}' | tr -d '\.'` ;
2021-06-14 13:56:42 +02:00
if ( ( $ pid > 0 ) && ( $ component_last_contact > 0 ) ) {
# service running but not all components
log_message ( $ conf , 'LOG' , 'Pandora service running but not all components.' ) ;
print ">> service running but delayed...\n" ;
2021-07-19 06:47:24 +02:00
$ control_command = "restart-server" ;
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "restart_server" ;
}
`$Pandora_Service $control_command 2>/dev/null` ;
2021-06-14 13:56:42 +02:00
} elsif ( $ pid == 0 ) {
# service not running
log_message ( $ conf , 'LOG' , 'Pandora service not running.' ) ;
print ">> service not running...\n" ;
2021-07-19 06:47:24 +02:00
$ control_command = "start-server" ;
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "start_server" ;
}
`$Pandora_Service $control_command 2>/dev/null` ;
2021-06-14 13:56:42 +02:00
} elsif ( $ pid > 0
&& $ nservers == 0
) {
my @ server_list = get_enabled_servers ( $ conf ) ;
my $ nservers = $# server_list ;
# Process running but no servers active, restart.
# Try to restart pandora_server if no servers are found.
# Do not restart if is a configuration issue.
log_message ( $ conf , 'LOG' , 'Pandora service running without servers [' . $ nservers . '].' ) ;
if ( $ nservers >= 0 ) {
log_message ( $ conf , 'LOG' , 'Restarting Pandora service...' ) ;
2021-07-19 06:47:24 +02:00
$ control_command = "restart-server" ;
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "restart_server" ;
}
`$Pandora_Service $control_command 2>/dev/null` ;
2021-06-14 13:56:42 +02:00
}
}
}
2023-10-10 11:04:25 +02:00
##############################################################################
# Keep MADE running
##############################################################################
sub ha_keep_made_running ($$) {
my ( $ conf , $ dbh ) = @ _ ;
# Is MADE enabled?
return unless ( defined ( $ conf - > { 'madeserver' } ) && $ conf - > { 'madeserver' } == 1 ) ;
# Is MADE installed?
`$conf->{'made_service_cmd'} status 2>/dev/null` ;
if ( ( $? >> 8 ) == 4 ) {
log_message ( $ conf , 'LOG' , "Pandora FMS MADE is not installed." ) ;
return ;
}
# Try to get the PID of the service.
my $ pid = `systemctl show --property MainPID pandora_made | cut -d= -f2` ;
chomp ( $ pid ) ;
if ( $ pid eq "0" ) {
log_message ( $ conf , 'LOG' , 'MADE service not running.' ) ;
`$conf->{'made_service_cmd'} start 2>/dev/null` ;
}
}
2022-04-13 13:14:54 +02:00
##############################################################################
# Keep the Tentacle server running
##############################################################################
sub ha_keep_tentacle_running ($$) {
my ( $ conf , $ dbh ) = @ _ ;
return unless ( $ conf - > { 'tentacle_service_watchdog' } == 1 ) ;
# Try to get the PID of the service.
my $ pid = `$conf->{'tentacle_service_cmd'} status | awk '{print \$NF*1}' | tr -d '\.'` ;
# Not running.
if ( $ pid == 0 ) {
log_message ( $ conf , 'LOG' , 'Tentacle service not running.' ) ;
print ">> service not running...\n" ;
`$conf->{'tentacle_service_cmd'} start 2>/dev/null` ;
}
}
2021-06-14 13:56:42 +02:00
###############################################################################
# Update pandora services.
###############################################################################
sub ha_update_server ($$) {
my ( $ config , $ dbh ) = @ _ ;
2021-07-19 06:47:24 +02:00
my $ OSNAME = $^O ;
2021-06-14 13:56:42 +02:00
my $ repoServer = pandora_get_tconfig_token (
$ dbh , 'remote_config' , '/var/spool/pandora/data_in'
) ;
$ repoServer . = '/updates/server/' ;
my $ lockFile = $ repoServer . '/' . $ config - > { 'servername' } . '.installed' ;
my $ workDir = $ config - > { "temporal" } . '/server_update/' ;
my $ versionFile = $ repoServer . 'version.txt' ;
return if ( - e $ lockFile ) || ( ! - e $ versionFile ) ;
log_message ( $ config , 'LOG' , 'Detected server update: ' . `cat "$versionFile"` ) ;
if ( ! - e "$workDir" && ! mkdir ( $ workDir ) ) {
log_message ( $ config , 'ERROR' , 'Server update failed: ' . $! ) ;
return ;
}
my $ r = `cd "$workDir/" && tar xzf "$repoServer/pandorafms_server.tar.gz" 2>&1` ;
if ( $? ne 0 ) {
log_message ( $ config , 'ERROR' , 'Failed to uncompress file: ' . $ r ) ;
return ;
}
$ r = `cd "$workDir/pandora_server/" && ./pandora_server_installer --install 2>&1 >/dev/null` ;
if ( $? ne 0 ) {
log_message ( $ config , 'ERROR' , 'Failed to install server update: ' . $ r ) ;
return ;
} else {
log_message ( $ config , 'LOG' , 'Server update ' . `cat "$versionFile"` . ' installed' ) ;
}
# Cleanup
rmtree ( $ workDir ) ;
# Restart service
2021-07-19 06:47:24 +02:00
my $ control_command = "restart-server" ;
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "restart_server" ;
}
`$config->{'pandora_service_cmd'} $control_command 2>/dev/null` ;
2021-06-14 13:56:42 +02:00
`touch "$lockFile"` ;
# After apply update, permission over files are changed, allow group to
# modify/delete files.
`chmod 770 "$repoServer"` ;
`chmod 770 "$repoServer/../"` ;
`chmod 660 "$repoServer"/*` ;
}
2024-02-12 14:58:00 +01:00
###############################################################################
# Restart pandora server on demand.
###############################################################################
sub ha_restart_server ($$) {
my ( $ config , $ dbh ) = @ _ ;
my $ OSNAME = $^O ;
my $ current_license ;
if ( ! defined ( $ License ) ) {
$ License = get_db_value ( $ dbh , 'SELECT `value` FROM `tupdate_settings` WHERE `key` = "customer_key"' ) ;
$ current_license = $ License ;
} else {
$ current_license = get_db_value ( $ dbh , 'SELECT `value` FROM `tupdate_settings` WHERE `key` = "customer_key"' ) ;
}
if ( $ License ne $ current_license ) {
ha_restart_pandora ( $ config ) ;
$ License = $ current_license ;
}
}
2023-03-15 12:48:47 +01:00
################################################################################
# Dump the list of known databases to disk.
################################################################################
sub ha_dump_databases ($) {
my ( $ conf ) = @ _ ;
# HA is not configured.
return unless defined ( $ conf - > { 'ha_hosts' } ) ;
eval {
open ( my $ fh , '>' , $ conf - > { 'ha_hosts_file' } ) ;
print $ fh $ DB_Host ; # The console only needs the master DB.
close ( $ fh ) ;
log_message ( $ conf , 'DEBUG' , "Dumped master database $DB_Host to disk" ) ;
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
}
################################################################################
# Read the list of known databases from disk.
################################################################################
sub ha_load_databases ($) {
my ( $ conf ) = @ _ ;
# HA is not configured.
return unless defined ( $ conf - > { 'ha_hosts' } ) ;
@ HA_DB_Hosts = grep { ! /^#/ } map { s/^\s+|\s+$//g ; $ _ ; } split ( /,/ , $ conf - > { 'ha_hosts' } ) ;
2023-08-02 02:14:11 +02:00
log_message ( $ conf , 'DEBUG' , "Loaded databases from disk (@HA_DB_Hosts)" ) ;
2023-03-15 12:48:47 +01:00
}
2021-06-14 13:56:42 +02:00
###############################################################################
# Connect to ha database, falling back to direct connection to db.
###############################################################################
sub ha_database_connect ($) {
my $ conf = shift ;
my $ dbh = enterprise_hook ( 'ha_connect' , [ $ conf ] ) ;
if ( ! defined ( $ dbh ) ) {
$ dbh = db_connect ( 'mysql' , $ conf - > { 'dbname' } , $ conf - > { 'dbhost' } , $ conf - > { 'dbport' } , $ conf - > { 'dbuser' } , $ conf - > { 'dbpass' } ) ;
}
return $ dbh ;
}
###############################################################################
2023-03-15 12:48:47 +01:00
# Connect to ha database, falling back to direct connection to db.
###############################################################################
sub ha_database_connect_pandora ($) {
my $ conf = shift ;
my $ dbhost = $ conf - > { 'dbhost' } ;
# Load the list of HA databases.
ha_load_databases ( $ conf ) ;
2023-08-02 02:14:11 +02:00
2023-03-15 12:48:47 +01:00
# Select a new master database.
my ( $ dbh , $ utimestamp , $ max_utimestamp ) = ( undef , undef , - 1 ) ;
2023-08-02 02:14:11 +02:00
2023-03-15 12:48:47 +01:00
foreach my $ ha_dbhost ( @ HA_DB_Hosts ) {
# Retry each database ha_connect_retries times.
for ( my $ i = 0 ; $ i < $ conf - > { 'ha_connect_retries' } ; $ i + + ) {
eval {
log_message ( $ conf , 'DEBUG' , "Trying database $ha_dbhost..." ) ;
$ dbh = db_connect ( 'mysql' ,
$ conf - > { 'dbname' } ,
$ ha_dbhost ,
$ conf - > { 'dbport' } ,
$ conf - > { 'ha_dbuser' } ,
$ conf - > { 'ha_dbpass' } ) ;
log_message ( $ conf , 'DEBUG' , "Connected to database $ha_dbhost" ) ;
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
# Connection successful.
last if defined ( $ dbh ) ;
# Wait for the next retry.
sleep ( $ conf - > { 'ha_connect_delay' } ) ;
}
# No luck. Try the next database.
next unless defined ( $ dbh ) ;
2024-02-22 15:45:04 +01:00
# Check if database is disabled.
if ( defined ( get_db_value ( $ dbh , 'SELECT `id` FROM `tdatabase` WHERE `host` = "' . $ ha_dbhost . '" AND disabled = 1' ) ) )
{
log_message ( $ conf , 'LOG' , "Ignoring disabled host: " . $ ha_dbhost ) ;
db_disconnect ( $ dbh ) ;
next ;
}
2023-03-15 12:48:47 +01:00
eval {
# Get the most recent utimestamp from the database.
$ utimestamp = get_db_value ( $ dbh , 'SELECT UNIX_TIMESTAMP(MAX(keepalive)) FROM tserver' ) ;
db_disconnect ( $ dbh ) ;
# Did we find a more recent database?
$ utimestamp = 0 unless defined ( $ utimestamp ) ;
if ( $ utimestamp > $ max_utimestamp ) {
$ dbhost = $ ha_dbhost ;
$ max_utimestamp = $ utimestamp ;
}
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
}
# Return a connection to the selected master.
eval {
log_message ( $ conf , 'DEBUG' , "Connecting to selected master $dbhost..." ) ;
$ dbh = db_connect ( 'mysql' ,
$ conf - > { 'dbname' } ,
$ dbhost ,
$ conf - > { 'dbport' } ,
$ conf - > { 'ha_dbuser' } ,
$ conf - > { 'ha_dbpass' } ) ;
# Restart if a new master was selected.
if ( $ dbhost ne $ DB_Host ) {
log_message ( $ conf , 'DEBUG' , "Setting master database to $dbhost" ) ;
$ DB_Host = $ dbhost ;
$ Restart = 1 ;
}
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
# Save the list of HA databases.
ha_dump_databases ( $ conf ) ;
return $ dbh ;
}
###############################################################################
# Return 1 if the given DB is read-only, 0 otherwise.
###############################################################################
sub ha_read_only ($$) {
my ( $ conf , $ dbh ) = @ _ ;
my $ read_only = get_db_value ( $ dbh , 'SELECT @@global.read_only' ) ;
return 1 if ( defined ( $ read_only ) && $ read_only == 1 ) ;
return 0 ;
}
###############################################################################
# Restart the Pandora FMS Server.
###############################################################################
sub ha_restart_pandora ($) {
my ( $ config ) = @ _ ;
my $ control_command = $^O eq 'freebsd' ?
'restart_server' :
'restart-server' ;
`$config->{'pandora_service_cmd'} $control_command 2>/dev/null` ;
}
2023-08-02 02:14:11 +02:00
###############################################################################
2023-03-15 12:48:47 +01:00
# Main (Pacemaker)
2021-06-14 13:56:42 +02:00
###############################################################################
2023-03-15 12:48:47 +01:00
sub ha_main_pacemaker ($) {
2021-06-14 13:56:42 +02:00
my ( $ conf ) = @ _ ;
# Set the PID file.
$ conf - > { 'PID' } = $ PID_FILE ;
# Log to a separate file if needed.
$ conf - > { 'log_file' } = $ conf - > { 'ha_log_file' } if defined ( $ conf - > { 'ha_log_file' } ) ;
$ Running = 1 ;
2022-03-09 13:46:40 +01:00
ha_daemonize ( $ conf ) if ( $ DAEMON == 1 ) ;
2021-06-14 13:56:42 +02:00
while ( $ Running ) {
eval {
2021-06-14 19:18:45 +02:00
eval {
local $ SIG { __DIE__ } ;
# Load enterprise components.
enterprise_load ( $ conf , 1 ) ;
# Register Enterprise logger
enterprise_hook ( 'pandoraha_logger' , [ \ & log_message ] ) ;
log_message ( $ conf , 'LOG' , 'Enterprise capabilities loaded' ) ;
} ;
if ( $@ ) {
# No enterprise capabilities.
log_message ( $ conf , 'LOG' , 'No enterprise capabilities' ) ;
}
2021-06-14 13:56:42 +02:00
# Start the Pandora FMS server if needed.
log_message ( $ conf , 'LOG' , 'Checking the pandora_server service.' ) ;
# Connect to a DB.
my $ dbh = ha_database_connect ( $ conf ) ;
if ( $ First_Cleanup == 1 ) {
log_message ( $ conf , 'LOG' , 'Cleaning previous unfinished actions' ) ;
enterprise_hook ( 'pandoraha_cleanup_states' , [ $ conf , $ dbh ] ) ;
$ First_Cleanup = 0 ;
}
# Check if there are updates pending.
ha_update_server ( $ conf , $ dbh ) ;
# Keep pandora running
ha_keep_pandora_running ( $ conf , $ dbh ) ;
2022-04-13 13:14:54 +02:00
# Keep Tentacle running
ha_keep_tentacle_running ( $ conf , $ dbh ) ;
2021-06-14 13:56:42 +02:00
2023-10-10 11:04:25 +02:00
# Keep MADE running
ha_keep_made_running ( $ conf , $ dbh ) ;
2021-06-14 13:56:42 +02:00
# Are we the master?
pandora_set_master ( $ conf , $ dbh ) ;
if ( ! pandora_is_master ( $ conf ) ) {
log_message ( $ conf , 'LOG' , $ conf - > { 'servername' } . ' is not the current master. Skipping DB-HA actions and monitoring.' ) ;
# Exit current eval.
return ;
}
2021-06-14 19:18:45 +02:00
# Synchronize database.
enterprise_hook ( 'pandoraha_sync_node' , [ $ conf , $ dbh ] ) ;
2021-06-14 13:56:42 +02:00
# Monitoring.
enterprise_hook ( 'pandoraha_monitoring' , [ $ conf , $ dbh ] ) ;
# Pending actions.
enterprise_hook ( 'pandoraha_process_queue' , [ $ conf , $ dbh , $ First_Cleanup ] ) ;
# Cleanup and exit
db_disconnect ( $ dbh ) ;
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
log_message ( $ conf , 'LOG' , "Sleep." ) ;
sleep ( $ conf - > { 'ha_interval' } ) ;
}
}
2023-03-15 12:48:47 +01:00
###############################################################################
# Main (Pandora)
###############################################################################
sub ha_main_pandora ($) {
my ( $ conf ) = @ _ ;
# Set the PID file.
$ conf - > { 'PID' } = $ PID_FILE ;
# Log to a separate file if needed.
$ conf - > { 'log_file' } = $ conf - > { 'ha_log_file' } if defined ( $ conf - > { 'ha_log_file' } ) ;
# Run in the background.
ha_daemonize ( $ conf ) if ( $ DAEMON == 1 ) ;
# Main loop.
$ Running = 1 ;
while ( $ Running ) {
my $ dbh = undef ;
eval {
# Connect to a DB.
log_message ( $ conf , 'LOG' , "Looking for databases" ) ;
$ dbh = ha_database_connect_pandora ( $ conf ) ;
if ( ! defined ( $ dbh ) ) {
log_message ( $ conf , 'LOG' , 'No databases available' ) ;
return ;
}
# Make the DB host available to the Pandora FMS Server.
$ ENV { 'PANDORA_DBHOST' } = $ DB_Host ;
# Needed for the Enterprise module.
$ conf - > { 'dbhost' } = $ DB_Host ;
# Enterprise capabilities need access to the DB.
eval {
local $ SIG { __DIE__ } ;
# Load enterprise components.
enterprise_load ( $ conf , 1 ) ;
# Register Enterprise logger
enterprise_hook ( 'pandoraha_logger' , [ \ & log_message ] ) ;
log_message ( $ conf , 'LOG' , 'Enterprise capabilities loaded' ) ;
} ;
log_message ( $ conf , 'LOG' , "No enterprise capabilities: $@" ) if ( $@ ) ;
log_message ( $ conf , 'LOG' , "Connected to database $DB_Host" ) ;
enterprise_hook ( 'pandoraha_stop_slave' , [ $ conf , $ dbh ] ) ;
if ( ha_read_only ( $ conf , $ dbh ) == 1 ) {
log_message ( $ conf , 'LOG' , "The database is read-only." ) ;
return ;
}
# Check if there are updates pending.
ha_update_server ( $ conf , $ dbh ) ;
2024-02-12 14:58:00 +01:00
# Check restart server on demand.
ha_restart_server ( $ conf , $ dbh ) ;
2023-03-15 12:48:47 +01:00
# Keep pandora running
ha_keep_pandora_running ( $ conf , $ dbh ) ;
# Keep Tentacle running
ha_keep_tentacle_running ( $ conf , $ dbh ) ;
2023-10-10 11:04:25 +02:00
# Keep MADE running
ha_keep_made_running ( $ conf , $ dbh ) ;
2023-03-15 12:48:47 +01:00
# Are we the master?
pandora_set_master ( $ conf , $ dbh ) ;
if ( ! pandora_is_master ( $ conf ) ) {
log_message ( $ conf , 'LOG' , $ conf - > { 'servername' } . ' is not the current master. Skipping DB-HA actions and monitoring.' ) ;
return ;
}
# Check the status of slave databases.
enterprise_hook ( 'pandoraha_check_slaves' , [ $ conf , $ dbh , $ DB_Host , \ @ HA_DB_Hosts ] ) ;
# Update the status of HA databases.
enterprise_hook ( 'pandoraha_update_dbs' , [ $ conf , $ dbh , $ DB_Host , \ @ HA_DB_Hosts ] ) ;
# Execute resync actions.
enterprise_hook ( 'pandoraha_resync_dbs' , [ $ conf , $ dbh , $ DB_Host , \ @ HA_DB_Hosts ] ) ;
2023-03-29 14:02:35 +02:00
2024-02-20 14:01:32 +01:00
# Update and push HA databases info to Metaconsole or nodes.
enterprise_hook ( 'pandoraha_update_and_push_databases_info' , [ $ conf , $ dbh ] ) ;
2023-03-29 14:02:35 +02:00
# Synchronize nodes.
enterprise_hook ( 'pandoraha_sync_node' , [ $ conf , $ dbh ] ) ;
2023-03-15 12:48:47 +01:00
} ;
log_message ( $ conf , 'WARNING' , $@ ) if ( $@ ) ;
# Cleanup.
eval {
db_disconnect ( $ dbh ) if defined ( $ dbh ) ;
} ;
# Go to sleep.
log_message ( $ conf , 'LOG' , "Sleep." ) ;
sleep ( $ conf - > { 'ha_interval' } ) ;
}
}
2021-06-14 13:56:42 +02:00
################################################################################
# Stop pandora server
################################################################################
sub stop {
2021-07-19 06:47:24 +02:00
my $ OSNAME = $^O ;
2021-06-14 13:56:42 +02:00
if ( $ Running == 1 ) {
$ Running = 0 ;
# cleanup and stop pandora_server
print ">> stopping server...\n" ;
2021-07-19 06:47:24 +02:00
my $ control_command = "stop-server" ;
if ( $ OSNAME eq "freebsd" ) {
$ control_command = "stop_server" ;
}
`$Pandora_Service $control_command 2>/dev/null` ;
2021-06-14 13:56:42 +02:00
}
}
################################################################################
# END block.
################################################################################
END {
stop ( ) ;
}
$ SIG { INT } = \ & stop ;
$ SIG { TERM } = \ & stop ;
# Init
ha_init_pandora ( \ % Conf ) ;
# Read config file
ha_load_pandora_conf ( \ % Conf ) ;
# Main
2023-03-15 12:48:47 +01:00
if ( defined ( $ Conf { 'ha_mode' } ) && lc ( $ Conf { 'ha_mode' } ) eq 'pandora' ) {
ha_main_pandora ( \ % Conf ) ;
} else {
ha_main_pacemaker ( \ % Conf ) ;
}
2021-06-14 13:56:42 +02:00
exit 0 ;