#!/usr/bin/perl # --------------------------------------------------------------- # Copyright (C) 2008 Georgia Public Library Service # Bill Erickson # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # --------------------------------------------------------------- use strict; use warnings; use Getopt::Long; use Net::Domain qw/hostfqdn/; use POSIX qw/setsid :sys_wait_h/; use OpenSRF::Utils::Logger q/$logger/; use OpenSRF::System; use OpenSRF::Transport::PeerHandle; use OpenSRF::Utils::SettingsClient; use OpenSRF::Transport::Listener; use OpenSRF::Utils; use OpenSRF::Utils::Config; my $opt_action = undef; my $opt_service = undef; my $opt_config = "@sysconfdir@/opensrf_core.xml"; my $opt_pid_dir = "@TMP@"; my $opt_no_daemon = 0; my $opt_settings_pause = 0; my $opt_localhost = 0; my $opt_help = 0; my $verbose = 0; my $sclient; my $hostname = $ENV{OSRF_HOSTNAME} || hostfqdn(); my @hosted_services; GetOptions( 'action=s' => \$opt_action, 'service=s' => \$opt_service, 'config=s' => \$opt_config, 'pid-dir=s' => \$opt_pid_dir, 'no-daemon' => \$opt_no_daemon, 'settings-startup-pause=i' => \$opt_settings_pause, 'localhost' => \$opt_localhost, 'help' => \$opt_help, 'verbose' => \$verbose, ); if ($opt_localhost) { $hostname = 'localhost'; $ENV{OSRF_HOSTNAME} = $hostname; } sub haltme { kill('INT', -$$); #kill all in process group exit; }; $SIG{INT} = \&haltme; $SIG{TERM} = \&haltme; sub get_pid_file { my $service = shift; return "$opt_pid_dir/$service.pid"; } # stop a specific service sub do_stop { my $service = shift; my $pid_file = get_pid_file($service); if(-e $pid_file) { my $pid = `cat $pid_file`; chomp $pid; msg("stopping service pid=$pid $service", 1); kill('INT', $pid); waitpid($pid, 0); unlink $pid_file; } else { msg("$service not running"); } return 1; } sub do_init { OpenSRF::System->bootstrap_client(config_file => $opt_config); die "Unable to bootstrap client for requests\n" unless OpenSRF::Transport::PeerHandle->retrieve; load_settings(); # load the settings config if we can my $sclient = OpenSRF::Utils::SettingsClient->new; my $apps = $sclient->config_value("activeapps", "appname"); # disconnect the top-level network handle OpenSRF::Transport::PeerHandle->retrieve->disconnect; if($apps) { $apps = [$apps] unless ref $apps; for my $app (@$apps) { push(@hosted_services, $app) if $sclient->config_value('apps', $app, 'language') =~ /perl/i; } } return 1; } # start a specific service sub do_start { my $service = shift; if(-e get_pid_file($service)) { msg("$service is already running"); return; } load_settings() if $service eq 'opensrf.settings'; my $sclient = OpenSRF::Utils::SettingsClient->new; my $apps = $sclient->config_value("activeapps", "appname"); OpenSRF::Transport::PeerHandle->retrieve->disconnect; if(grep { $_ eq $service } @hosted_services) { return unless do_daemon($service); launch_net_server($service); launch_listener($service); $0 = "OpenSRF controller [$service]"; while(my $pid = waitpid(-1, 0)) { $logger->debug("Cleaning up Perl $service process $pid"); } } msg("$service is not configured to run on $hostname"); return 1; } sub do_start_all { msg("starting all services for $hostname", 1); if(grep {$_ eq 'opensrf.settings'} @hosted_services) { do_start('opensrf.settings'); # in batch mode, give opensrf.settings plenty of time to start # before any non-Perl services try to connect sleep $opt_settings_pause if $opt_settings_pause; } for my $service (@hosted_services) { do_start($service) unless $service eq 'opensrf.settings'; } return 1; } sub do_stop_all { msg("stopping all services for $hostname", 1); do_stop($_) for @hosted_services; return 1; } # daemonize us. return true if we're the child, false if parent sub do_daemon { return 1 if $opt_no_daemon; my $service = shift; my $pid_file = get_pid_file($service); #exit if OpenSRF::Utils::safe_fork(); return 0 if OpenSRF::Utils::safe_fork(); msg("starting service pid=$$ $service", 1); chdir('/'); setsid(); close STDIN; close STDOUT; close STDERR; `echo $$ > $pid_file`; return 1; } # parses the local settings file sub load_settings { my $conf = OpenSRF::Utils::Config->current; my $cfile = $conf->bootstrap->settings_config; return unless $cfile; my $parser = OpenSRF::Utils::SettingsParser->new(); $parser->initialize( $cfile ); $OpenSRF::Utils::SettingsClient::host_config = $parser->get_server_config($conf->env->hostname); } # starts up the unix::server master process sub launch_net_server { my $service = shift; push @OpenSRF::UnixServer::ISA, 'Net::Server::PreFork'; unless(OpenSRF::Utils::safe_fork()) { $0 = "OpenSRF Drone [$service]"; OpenSRF::UnixServer->new($service)->serve; exit; } return 1; } # starts up the inbound listener process sub launch_listener { my $service = shift; unless(OpenSRF::Utils::safe_fork()) { $0 = "OpenSRF listener [$service]"; OpenSRF::Transport::Listener->new($service)->initialize->listen; exit; } return 1; } sub msg { my $m = shift; my $v = shift; print "* $m\n" unless $v and not $verbose; } sub do_help { print < Actions include start, stop, restart, and start_all, stop_all, and restart_all --service Specifies which OpenSRF service to control --config OpenSRF configuration file --pid-dir Directory where process-specific PID files are kept --no-daemon Do not detach and run as a daemon process. Useful for debugging. --settings-startup-pause How long to give the opensrf.settings server to start up when running in batch mode (start_all). The purpose is to give plenty of time for the settings server to be up and active before any non-Perl services attempt to connect. --localhost Force the hostname to be 'localhost', instead of the fully qualified domain name for the machine. --help Print this help message HELP exit; } do_help() if $opt_help or not $opt_action; do_init() and do_start($opt_service) if $opt_action eq 'start'; do_stop($opt_service) if $opt_action eq 'stop'; do_init() and do_stop($opt_service) and do_start($opt_service) if $opt_action eq 'restart'; do_init() and do_start_all() if $opt_action eq 'start_all'; do_init() and do_stop_all() if $opt_action eq 'stop_all'; do_init() and do_stop_all() and do_start_all() if $opt_action eq 'restart_all';