Adding comments and tinkering with white space.
[OpenSRF.git] / bin / opensrf-perl.pl.in
1 #!/usr/bin/perl
2 # ---------------------------------------------------------------
3 # Copyright (C) 2008  Georgia Public Library Service
4 # Bill Erickson <erickson@esilibrary.com>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 # ---------------------------------------------------------------
16 use strict; use warnings;
17 use Getopt::Long;
18 use Net::Domain qw/hostfqdn/;
19 use POSIX qw/setsid :sys_wait_h/;
20 use OpenSRF::Utils::Logger q/$logger/;
21 use OpenSRF::System;
22 use OpenSRF::Transport::PeerHandle;
23 use OpenSRF::Utils::SettingsClient;
24 use OpenSRF::Transport::Listener;
25 use OpenSRF::Utils;
26 use OpenSRF::Utils::Config;
27
28 my $opt_action = undef;
29 my $opt_service = undef;
30 my $opt_config = "@CONF_DIR@/opensrf_core.xml";
31 my $opt_pid_dir = "@PID_DIR@/run/opensrf";
32 my $opt_no_daemon = 0;
33 my $opt_settings_pause = 0;
34 my $opt_localhost = 0;
35 my $opt_help = 0;
36 my $verbose = 0;
37 my $sclient;
38 my $hostname = $ENV{OSRF_HOSTNAME} || hostfqdn();
39 my @hosted_services;
40
41 GetOptions(
42     'action=s' => \$opt_action,
43     'service=s' => \$opt_service,
44     'config=s' => \$opt_config,
45     'pid-dir=s' => \$opt_pid_dir,
46     'no-daemon' => \$opt_no_daemon,
47     'settings-startup-pause=i' => \$opt_settings_pause,
48     'localhost' => \$opt_localhost,
49     'help' => \$opt_help,
50     'verbose' => \$verbose,
51 );
52
53 if ($opt_localhost) {
54     $hostname = 'localhost';
55     $ENV{OSRF_HOSTNAME} = $hostname;
56 }
57
58 sub haltme {
59     kill('INT', -$$); #kill all in process group
60     exit;
61 };
62 $SIG{INT} = \&haltme;
63 $SIG{TERM} = \&haltme;
64
65 sub get_pid_file {
66     my $service = shift;
67     return "$opt_pid_dir/$service.pid";
68 }
69
70 # stop a specific service
71 sub do_stop {
72     my $service = shift;
73     my $pid_file = get_pid_file($service);
74     if(-e $pid_file) {
75         my $pid = `cat $pid_file`;
76         chomp $pid;
77         msg("stopping service pid=$pid $service", 1);
78         kill('INT', $pid);
79         waitpid($pid, 0);
80         unlink $pid_file;
81     } else {
82         msg("$service not running");
83     }
84     return 1;
85 }
86
87 sub do_init {
88     OpenSRF::System->bootstrap_client(config_file => $opt_config);
89     die "Unable to bootstrap client for requests\n"
90         unless OpenSRF::Transport::PeerHandle->retrieve;
91
92     load_settings(); # load the settings config if we can
93
94     my $sclient = OpenSRF::Utils::SettingsClient->new;
95     my $apps = $sclient->config_value("activeapps", "appname");
96
97     # disconnect the top-level network handle
98     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
99
100     if($apps) {
101         $apps = [$apps] unless ref $apps;
102         for my $app (@$apps) {
103             push(@hosted_services, $app) 
104                 if $sclient->config_value('apps', $app, 'language') =~ /perl/i;
105         }
106     }
107     return 1;
108 }
109
110 # start a specific service
111 sub do_start {
112     my $service = shift;
113     if(-e get_pid_file($service)) {
114         msg("$service is already running");
115         return;
116     }
117
118     load_settings() if $service eq 'opensrf.settings';
119
120     my $sclient = OpenSRF::Utils::SettingsClient->new;
121     my $apps = $sclient->config_value("activeapps", "appname");
122     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
123
124     if(grep { $_ eq $service } @hosted_services) {
125         return unless do_daemon($service);
126         launch_net_server($service);
127         launch_listener($service);
128         $0 = "OpenSRF controller [$service]";
129         while(my $pid = waitpid(-1, 0)) {
130             last if $pid == -1;
131             $logger->debug("Cleaning up Perl $service process $pid");
132         }
133     }
134
135     msg("$service is not configured to run on $hostname");
136     return 1;
137 }
138
139 sub do_start_all {
140     msg("starting all services for $hostname", 1);
141     if(grep {$_ eq 'opensrf.settings'} @hosted_services) {
142         do_start('opensrf.settings');
143         # in batch mode, give opensrf.settings plenty of time to start 
144         # before any non-Perl services try to connect
145         sleep $opt_settings_pause if $opt_settings_pause;
146     }
147     for my $service (@hosted_services) {
148         do_start($service) unless $service eq 'opensrf.settings';
149     }
150     return 1;
151 }
152
153 sub do_stop_all {
154     msg("stopping all services for $hostname", 1);
155     do_stop($_) for @hosted_services;
156     return 1;
157 }
158
159 # daemonize us.  return true if we're the child, false if parent
160 sub do_daemon {
161     return 1 if $opt_no_daemon;
162     my $service = shift;
163     my $pid_file = get_pid_file($service);
164     #exit if OpenSRF::Utils::safe_fork();
165     return 0 if OpenSRF::Utils::safe_fork();
166     msg("starting service pid=$$ $service", 1);
167     chdir('/');
168     setsid();
169     close STDIN;
170     close STDOUT;
171     close STDERR;
172     `echo $$ > $pid_file`;
173     return 1;
174 }
175
176 # parses the local settings file
177 sub load_settings {
178     my $conf = OpenSRF::Utils::Config->current;
179     my $cfile = $conf->bootstrap->settings_config;
180     return unless $cfile;
181     my $parser = OpenSRF::Utils::SettingsParser->new();
182     $parser->initialize( $cfile );
183     $OpenSRF::Utils::SettingsClient::host_config =
184         $parser->get_server_config($conf->env->hostname);
185 }
186
187 # starts up the unix::server master process
188 sub launch_net_server {
189     my $service = shift;
190     push @OpenSRF::UnixServer::ISA, 'Net::Server::PreFork';
191     unless(OpenSRF::Utils::safe_fork()) {
192         $0 = "OpenSRF Drone [$service]";
193         OpenSRF::UnixServer->new($service)->serve;
194         exit;
195     }
196     return 1;
197 }
198
199 # starts up the inbound listener process
200 sub launch_listener {
201     my $service = shift;
202     unless(OpenSRF::Utils::safe_fork()) {
203         $0 = "OpenSRF listener [$service]";
204         OpenSRF::Transport::Listener->new($service)->initialize->listen;
205         exit;
206     }
207     return 1;
208 }
209
210 sub msg {
211     my $m = shift;
212     my $v = shift;
213     print "* $m\n" unless $v and not $verbose;
214 }
215
216 sub do_help {
217     print <<HELP;
218
219     Usage: perl $0 --pid-dir @TMP@ --config @CONF_DIR@/opensrf_core.xml --service opensrf.settings --action start
220
221     --action <action>
222         Actions include start, stop, restart, and start_all, stop_all, and restart_all
223
224     --service <service>
225         Specifies which OpenSRF service to control
226
227     --config <file>
228         OpenSRF configuration file 
229         
230     --pid-dir <dir>
231         Directory where process-specific PID files are kept
232         
233     --no-daemon
234         Do not detach and run as a daemon process.  Useful for debugging.
235
236     --settings-startup-pause
237         How long to give the opensrf.settings server to start up when running 
238         in batch mode (start_all).  The purpose is to give plenty of time for
239         the settings server to be up and active before any non-Perl services
240         attempt to connect.
241
242     --localhost
243         Force the hostname to be 'localhost', instead of the fully qualified
244         domain name for the machine.
245         
246     --help
247         Print this help message
248 HELP
249 exit;
250 }
251
252
253 do_help() if $opt_help or not $opt_action;
254 do_init() and do_start($opt_service) if $opt_action eq 'start';
255 do_stop($opt_service) if $opt_action eq 'stop';
256 do_init() and do_stop($opt_service) and do_start($opt_service) if $opt_action eq 'restart';
257 do_init() and do_start_all() if $opt_action eq 'start_all';
258 do_init() and do_stop_all() if $opt_action eq 'stop_all';
259 do_init() and do_stop_all() and do_start_all() if $opt_action eq 'restart_all';
260
261