From 0ec78e231b6c08a525c59964b768842c74c90922 Mon Sep 17 00:00:00 2001 From: ramonn Date: Tue, 13 May 2014 13:34:57 +0000 Subject: [PATCH] 2014-05-13 Ramon Novoa * bin/pandora_server: Added support to run as a native win32 service. git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@9924 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f --- pandora_server/ChangeLog | 4 + pandora_server/bin/pandora_server | 381 +++++++++++++++++++++--------- 2 files changed, 277 insertions(+), 108 deletions(-) diff --git a/pandora_server/ChangeLog b/pandora_server/ChangeLog index d2f90cb64c..32db104734 100644 --- a/pandora_server/ChangeLog +++ b/pandora_server/ChangeLog @@ -1,3 +1,7 @@ +2014-05-13 Ramon Novoa + + * bin/pandora_server: Added support to run as a native win32 service. + 2014-05-10 Junichi Satoh * util/recon_script/ipmi-recon.pl, util/recon_script/snmpdevices.pl, diff --git a/pandora_server/bin/pandora_server b/pandora_server/bin/pandora_server index cc5e2d27a8..ed951a1636 100755 --- a/pandora_server/bin/pandora_server +++ b/pandora_server/bin/pandora_server @@ -19,7 +19,9 @@ use strict; use warnings; +use Getopt::Std; use POSIX qw(strftime); +use threads; # Default lib dir for RPM and DEB packages use lib '/usr/lib/perl5'; @@ -37,10 +39,15 @@ use PandoraFMS::WMIServer; use PandoraFMS::PluginServer; use PandoraFMS::PredictionServer; +# Constants for Win32 services. +use constant WIN32_SERVICE_STOPPED => 0x01; +use constant WIN32_SERVICE_RUNNING => 0x04; + # Global vars -my %Config; +my %Config :shared; my @Servers; my $DBH; +my $RUN :shared = 1; ######################################################################################## # Server shutdown. Handler to do a controlled shutdown. @@ -243,7 +250,7 @@ sub pandora_server_tasks ($) { $pa_config->{'dbuser'}, $pa_config->{'dbpass'}); my $counter = 0; - while (1) { + while ($RUN == 1) { eval{ # TASKS EXECUTED EVERY 5 SECONDS (Low latency tasks) # -------------------------------------------------- @@ -331,134 +338,292 @@ sub pandora_server_tasks ($) { } } -$SIG{'TERM'} = 'pandora_shutdown'; -$SIG{'INT'} = 'pandora_shutdown'; +################################################################################ +## Install the Windows service. +################################################################################ +sub win32_install_service() { -# Error handler needs to be reviewed, Enterprise not found errors are too nasty :( -$SIG{__DIE__} = 'pandora_crash'; + # Load Win32::Daemon. + eval "use Win32::Daemon"; + die($@) if ($@); -# Prevent alarm from bombing the main thread when called within a thread -$SIG{'ALRM'} = 'IGNORE'; - -# Initialize -pandora_init(\%Config, 'Pandora FMS Server'); -pandora_load_config (\%Config); - -# Daemonize and put in background -if ($Config{'daemon'} == 1) { - print_message (\%Config, " [*] Backgrounding Pandora FMS Server process.\n", 1); - pandora_daemonize (\%Config); -} - -# Load enterprise module -if (enterprise_load (\%Config) == 0) { - print_message (\%Config, " [*] Pandora FMS Enterprise module not available.", 1); - logger (\%Config, " [*] Pandora FMS Enterprise module not available.", 1); -} else { - print_message (\%Config, " [*] Pandora FMS Enterprise module loaded.", 1); - logger (\%Config, " [*] Pandora FMS Enterprise module loaded.", 1); - - if($Config{'policy_manager'} == 1) { - # Start thread to patrol policy queue - threads->create('pandora_process_policy_queue', (\%Config))->detach(); - } + # Configure and install the service. + my $service_path = $0; + my $service_params = "-S run \"$ARGV[0]\""; + my %service_hash = ( + machine => '', + name => 'PANDORAFMSSRV', + display => 'Pandora FMS Server', + path => $service_path, + user => '', + pwd => '', + description => 'Pandora FMS Server http://pandorafms.com/', + parameters => $service_params + ); - if($Config{'event_replication'} == 1) { - # Start thread to process event replication - threads->create('pandora_process_event_replication', (\%Config))->detach(); + if (Win32::Daemon::CreateService(\%service_hash)) { + print "Successfully added.\n"; + exit 0; + } else { + print "Failed to add service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; } } -# Start the servers -pandora_startup (); +################################################################################ +## Install the Windows service. +################################################################################ +sub win32_uninstall_service() { -# Start thread to execute server tasks -threads->create('pandora_server_tasks', (\%Config))->detach(); + # Load Win32::Daemon. + eval "use Win32::Daemon"; + die($@) if ($@); -# Generate 'going up' events -foreach my $server (@Servers) { - $server->upEvent (); + # Uninstall the service. + if (Win32::Daemon::DeleteService('', 'PANDORAFMSSRV')) { + print "Successfully deleted.\n"; + exit 0; + } else { + print "Failed to delete service: " . Win32::FormatMessage(Win32::Daemon::GetLastError()) . "\n"; + exit 1; + } } -# Check if the Data Server has too many threads -if ($Config{'dataserver_threads'} > 5) { - logger (\%Config, "[W] Server " . $Config{'servername'} . " have configured " . $Config{'dataserver_threads'} - . " threads for the data server. You should not use more than 5 threads for this server", 1); - print_message (\%Config, " [W] Server " . $Config{'servername'} . " have configured " . $Config{'dataserver_threads'} - . " threads for the data server. You should not use more than 5 threads for this server", 1); - pandora_event (\%Config, "Server " . $Config{'servername'} . " have configured " - . $Config{'dataserver_threads'} . " threads for the data server", 0, 0, 3, 0, 0, 'system', 0, $DBH); +################################################################################ +## Windows service callback function for the running event. +################################################################################ +sub callback_running { + if (Win32::Daemon::State() == WIN32_SERVICE_RUNNING) { + } } -# Check if the Pandora Server has too many threads -my $totalThreads = 0; -foreach my $server (@Servers) { - $totalThreads += $server->getNumThreads (); -} -if ($totalThreads > 40) { - logger (\%Config, '[W] Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads - . ' threads. This setup is not recommended, you should reduce the number of total threads below 40', 1); - print_message (\%Config, ' [W] Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads - . ' threads. This setup is not recommended, you should reduce the number of total threads below 40', 1); - pandora_event (\%Config, 'Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads - . ' threads', 0, 0, 3, 0, 0, 'system', 0, $DBH); +################################################################################ +## Windows service callback function for the start event. +################################################################################ +sub callback_start { + no strict; + + # Accept_connections (); + my $thr = threads->create(\&main); + if (!defined($thr)) { + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); + return; + } + $thr->detach(); + + Win32::Daemon::State(WIN32_SERVICE_RUNNING); } -# Check if the log verbosity is set to 10 -if ($Config{'verbosity'} == 10) { - logger (\%Config, '[W] Log verbosity is set to 10. This will degrade the server performance. Please set to a lower value ASAP', 1); - print_message (\%Config, ' [W] Log verbosity is set to 10. This will degrade the server performance. Please set to a lower value ASAP', 1); - pandora_event (\%Config, 'Log verbosity is set to 10. This will degrade the server performance', 0, 0, 1, 0, 0, 'system', 0, $DBH); +################################################################################ +## Windows service callback function for the stop event. +################################################################################ +sub callback_stop { + + $RUN = 0; + Win32::Daemon::State(WIN32_SERVICE_STOPPED); + Win32::Daemon::StopService(); } -# Main loop -my $time_ref = time (); -while (1) { - - eval { - - # Update server status - foreach my $server (@Servers) { - die ($server->getErrStr ()) unless ($server->checkThreads () == 1); - $server->update(); +################################################################################ +# Run as a Windows service. +################################################################################ +sub win32_service_run() { + + # Load Win32::Daemon. + eval "use Win32::Daemon"; + die($@) if ($@); + + # Run the Pandora FMS Server as a Windows service. + Win32::Daemon::RegisterCallbacks({ + start => \&callback_start, + running => \&callback_running, + stop => \&callback_stop, + }); + Win32::Daemon::StartService(); +} + +################################################################################ +## Parse command line options. +################################################################################ +sub parse_options { + my %opts; + my $tmp; + my @t_addresses_tmp; + + # Get options + if (getopts('S:', \%opts) == 0 || defined ($opts{'h'})) { + print_help (); + exit 1; + } + + # Win32 service management + if (defined ($opts{'S'})) { + my $service_action = $opts{'S'}; + if ($^O ne 'MSWin32') { + error ("Windows services are only available on Win32."); + } else { + eval "use Win32::Daemon"; + die($@) if ($@); + + if ($service_action eq 'install') { + win32_install_service(); + } elsif ($service_action eq 'uninstall') { + win32_uninstall_service(); + } elsif ($service_action eq 'run') { + win32_service_run; + } else { + error("Unknown action: $service_action"); + } } + } +} - # Not needed. The console assumes a server is down if it has not updated its status in the last 15 minutes. - ## Update fallen servers - #db_do ($DBH, "UPDATE tserver SET status = 0 WHERE keepalive < ?", strftime ("%Y-%m-%d %H:%M:%S", localtime(time() - $Config{'keepalive'}))); - }; +################################################################ +################################################################ +## Main. +################################################################ +################################################################ +sub main() { + + $SIG{'TERM'} = 'pandora_shutdown'; + $SIG{'INT'} = 'pandora_shutdown'; - # Restart on error or auto restart - if ($@) { - - if ($Config{'restart'} eq '0') { - print_message (\%Config, $@, 1); - pandora_shutdown (); + # Error handler needs to be reviewed, Enterprise not found errors are too nasty :( + $SIG{__DIE__} = 'pandora_crash'; + + # Prevent alarm from bombing the main thread when called within a thread + $SIG{'ALRM'} = 'IGNORE'; + + # Initialize + pandora_init(\%Config, 'Pandora FMS Server'); + pandora_load_config (\%Config); + + # Daemonize and put in background + if ($Config{'daemon'} == 1) { + print_message (\%Config, " [*] Backgrounding Pandora FMS Server process.\n", 1); + pandora_daemonize (\%Config); + } + + # Load enterprise module + if (enterprise_load (\%Config) == 0) { + print_message (\%Config, " [*] Pandora FMS Enterprise module not available.", 1); + logger (\%Config, " [*] Pandora FMS Enterprise module not available.", 1); + } else { + print_message (\%Config, " [*] Pandora FMS Enterprise module loaded.", 1); + logger (\%Config, " [*] Pandora FMS Enterprise module loaded.", 1); + + if($Config{'policy_manager'} == 1) { + # Start thread to patrol policy queue + threads->create('pandora_process_policy_queue', (\%Config))->detach(); } - # Generate 'restarting' events - foreach my $server (@Servers) { - $server->restartEvent ($@); + if($Config{'event_replication'} == 1) { + # Start thread to process event replication + threads->create('pandora_process_event_replication', (\%Config))->detach(); } - - logger (\%Config, 'Pandora FMS Server restarting (' . $@ . ') in ' . $Config{'restart_delay'} . ' seconds.', 1); - pandora_restart (); - } - elsif (($Config{'auto_restart'} > 0) && (time () - $time_ref > $Config{'auto_restart'})) { - $time_ref = time (); - - # Mute - open(OLDOUT, ">&STDOUT"); - open (STDOUT, '>/dev/null'); - - # Restart - pandora_restart (); - - # Unmute - open(STDOUT, ">&OLDOUT"); - close (OLDOUT); } - threads->yield; - sleep ($Config{'server_threshold'}); + # Start the servers + pandora_startup (); + + # Start thread to execute server tasks + threads->create('pandora_server_tasks', (\%Config))->detach(); + + # Generate 'going up' events + foreach my $server (@Servers) { + $server->upEvent (); + } + + # Check if the Data Server has too many threads + if ($Config{'dataserver_threads'} > 5) { + logger (\%Config, "[W] Server " . $Config{'servername'} . " have configured " . $Config{'dataserver_threads'} + . " threads for the data server. You should not use more than 5 threads for this server", 1); + print_message (\%Config, " [W] Server " . $Config{'servername'} . " have configured " . $Config{'dataserver_threads'} + . " threads for the data server. You should not use more than 5 threads for this server", 1); + pandora_event (\%Config, "Server " . $Config{'servername'} . " have configured " + . $Config{'dataserver_threads'} . " threads for the data server", 0, 0, 3, 0, 0, 'system', 0, $DBH); + } + + # Check if the Pandora Server has too many threads + my $totalThreads = 0; + foreach my $server (@Servers) { + $totalThreads += $server->getNumThreads (); + } + if ($totalThreads > 40) { + logger (\%Config, '[W] Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads + . ' threads. This setup is not recommended, you should reduce the number of total threads below 40', 1); + print_message (\%Config, ' [W] Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads + . ' threads. This setup is not recommended, you should reduce the number of total threads below 40', 1); + pandora_event (\%Config, 'Server ' . $Config{'servername'} . ' have configured a total of ' . $totalThreads + . ' threads', 0, 0, 3, 0, 0, 'system', 0, $DBH); + } + + # Check if the log verbosity is set to 10 + if ($Config{'verbosity'} == 10) { + logger (\%Config, '[W] Log verbosity is set to 10. This will degrade the server performance. Please set to a lower value ASAP', 1); + print_message (\%Config, ' [W] Log verbosity is set to 10. This will degrade the server performance. Please set to a lower value ASAP', 1); + pandora_event (\%Config, 'Log verbosity is set to 10. This will degrade the server performance', 0, 0, 1, 0, 0, 'system', 0, $DBH); + } + + # Main loop + my $time_ref = time (); + while ($RUN == 1) { + + eval { + + # Update server status + foreach my $server (@Servers) { + die ($server->getErrStr ()) unless ($server->checkThreads () == 1); + $server->update(); + } + + # Not needed. The console assumes a server is down if it has not updated its status in the last 15 minutes. + ## Update fallen servers + #db_do ($DBH, "UPDATE tserver SET status = 0 WHERE keepalive < ?", strftime ("%Y-%m-%d %H:%M:%S", localtime(time() - $Config{'keepalive'}))); + }; + + # Restart on error or auto restart + if ($@) { + + if ($Config{'restart'} eq '0') { + print_message (\%Config, $@, 1); + pandora_shutdown (); + } + + # Generate 'restarting' events + foreach my $server (@Servers) { + $server->restartEvent ($@); + } + + logger (\%Config, 'Pandora FMS Server restarting (' . $@ . ') in ' . $Config{'restart_delay'} . ' seconds.', 1); + pandora_restart (); + } + elsif (($Config{'auto_restart'} > 0) && (time () - $time_ref > $Config{'auto_restart'})) { + $time_ref = time (); + + # Mute + open(OLDOUT, ">&STDOUT"); + open (STDOUT, '>/dev/null'); + + # Restart + pandora_restart (); + + # Unmute + open(STDOUT, ">&OLDOUT"); + close (OLDOUT); + } + + threads->yield; + sleep ($Config{'server_threshold'}); + } + + pandora_shutdown(); } + +# Parse command line options. +parse_options; + +# Run as a regular process. +main(); +