Minor typo fix
[OpenSRF.git] / bin / opensrf-perl.pl
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 = undef;
31 my $opt_pid_dir = '/tmp';
32 my $opt_no_daemon = 0;
33 my $opt_settings_pause = 0;
34 my $opt_help = 0;
35 my $verbose = 0;
36 my $sclient;
37 my $hostname = hostfqdn();
38 my @hosted_services;
39
40 GetOptions(
41     'action=s' => \$opt_action,
42     'service=s' => \$opt_service,
43     'config=s' => \$opt_config,
44     'pid-dir=s' => \$opt_pid_dir,
45     'no-daemon' => \$opt_no_daemon,
46     'settings-startup-pause=i' => \$opt_settings_pause,
47     'help' => \$opt_help,
48     'verbose' => \$verbose,
49 );
50
51
52 sub haltme {
53     kill('INT', -$$); #kill all in process group
54     exit;
55 };
56 $SIG{INT} = \&haltme;
57 $SIG{TERM} = \&haltme;
58
59 sub get_pid_file {
60     my $service = shift;
61     return "$opt_pid_dir/$service.pid";
62 }
63
64 # stop a specific service
65 sub do_stop {
66     my $service = shift;
67     my $pid_file = get_pid_file($service);
68     if(-e $pid_file) {
69         my $pid = `cat $pid_file`;
70         chomp $pid;
71         msg("stopping service pid=$pid $service", 1);
72         kill('INT', $pid);
73         waitpid($pid, 0);
74         unlink $pid_file;
75     } else {
76         msg("$service not running");
77     }
78     return 1;
79 }
80
81 sub do_init {
82     OpenSRF::System->bootstrap_client(config_file => $opt_config);
83     die "Unable to bootstrap client for requests\n"
84         unless OpenSRF::Transport::PeerHandle->retrieve;
85
86     load_settings(); # load the settings config if we can
87
88     my $sclient = OpenSRF::Utils::SettingsClient->new;
89     my $apps = $sclient->config_value("activeapps", "appname");
90
91     # disconnect the top-level network handle
92     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
93
94     if($apps) {
95         $apps = [$apps] unless ref $apps;
96         for my $app (@$apps) {
97             push(@hosted_services, $app) 
98                 if $sclient->config_value('apps', $app, 'language') =~ /perl/i;
99         }
100     }
101     return 1;
102 }
103
104 # start a specific service
105 sub do_start {
106     my $service = shift;
107     if(-e get_pid_file($service)) {
108         msg("$service is already running");
109         return;
110     }
111
112     load_settings() if $service eq 'opensrf.settings';
113
114     my $sclient = OpenSRF::Utils::SettingsClient->new;
115     my $apps = $sclient->config_value("activeapps", "appname");
116     OpenSRF::Transport::PeerHandle->retrieve->disconnect;
117
118     if(grep { $_ eq $service } @hosted_services) {
119         return unless do_daemon($service);
120         launch_net_server($service);
121         launch_listener($service);
122         $0 = "OpenSRF controller [$service]";
123         while(my $pid = waitpid(-1, 0)) {
124             $logger->debug("Cleaning up Perl $service process $pid");
125         }
126     }
127
128     msg("$service is not configured to run on $hostname");
129     return 1;
130 }
131
132 sub do_start_all {
133     msg("starting all services for $hostname", 1);
134     if(grep {$_ eq 'opensrf.settings'} @hosted_services) {
135         do_start('opensrf.settings');
136         # in batch mode, give opensrf.settings plenty of time to start 
137         # before any non-Perl services try to connect
138         sleep $opt_settings_pause if $opt_settings_pause;
139     }
140     for my $service (@hosted_services) {
141         do_start($service) unless $service eq 'opensrf.settings';
142     }
143     return 1;
144 }
145
146 sub do_stop_all {
147     msg("stopping all services for $hostname", 1);
148     do_stop($_) for @hosted_services;
149     return 1;
150 }
151
152 # daemonize us.  return true if we're the child, false if parent
153 sub do_daemon {
154     return 1 if $opt_no_daemon;
155     my $service = shift;
156     my $pid_file = get_pid_file($service);
157     #exit if OpenSRF::Utils::safe_fork();
158     return 0 if OpenSRF::Utils::safe_fork();
159     msg("starting service pid=$$ $service", 1);
160     chdir('/');
161     setsid();
162     close STDIN;
163     close STDOUT;
164     close STDERR;
165     `echo $$ > $pid_file`;
166     return 1;
167 }
168
169 # parses the local settings file
170 sub load_settings {
171     my $conf = OpenSRF::Utils::Config->current;
172     my $cfile = $conf->bootstrap->settings_config;
173     return unless $cfile;
174     my $parser = OpenSRF::Utils::SettingsParser->new();
175     $parser->initialize( $cfile );
176     $OpenSRF::Utils::SettingsClient::host_config =
177         $parser->get_server_config($conf->env->hostname);
178 }
179
180 # starts up the unix::server master process
181 sub launch_net_server {
182     my $service = shift;
183     push @OpenSRF::UnixServer::ISA, 'Net::Server::PreFork';
184     unless(OpenSRF::Utils::safe_fork()) {
185         $0 = "OpenSRF Drone [$service]";
186         OpenSRF::UnixServer->new($service)->serve;
187         exit;
188     }
189     return 1;
190 }
191
192 # starts up the inbound listener process
193 sub launch_listener {
194     my $service = shift;
195     unless(OpenSRF::Utils::safe_fork()) {
196         $0 = "OpenSRF listener [$service]";
197         OpenSRF::Transport::Listener->new($service)->initialize->listen;
198         exit;
199     }
200     return 1;
201 }
202
203 sub msg {
204     my $m = shift;
205     my $v = shift;
206     print "* $m\n" unless $v and not $verbose;
207 }
208
209 sub do_help {
210     print <<HELP;
211
212     Usage: perl $0 --pid_dir /var/run/opensrf --config /etc/opensrf/opensrf_core.xml --service opensrf.settings --action start
213
214     --action <action>
215         Actions include start, stop, restart, and start_all, stop_all, and restart_all
216
217     --service <service>
218         Specifies which OpenSRF service to control
219
220     --config <file>
221         OpenSRF configuration file 
222         
223     --pid-dir <dir>
224         Directory where process-specific PID files are kept
225         
226     --no-daemon
227         Do not detach and run as a daemon process.  Useful for debugging.
228
229     --settings-startup-pause
230         How long to give the opensrf.settings server to start up when running 
231         in batch mode (start_all).  The purpose is to give plenty of time for
232         the settings server to be up and active before any non-Perl services
233         attempt to connect.
234         
235     --help
236         Print this help message
237 HELP
238 exit;
239 }
240
241
242 do_help() if $opt_help or not $opt_action;
243 do_init() and do_start($opt_service) if $opt_action eq 'start';
244 do_stop($opt_service) if $opt_action eq 'stop';
245 do_init() and do_stop($opt_service) and do_start($opt_service) if $opt_action eq 'restart';
246 do_init() and do_start_all() if $opt_action eq 'start_all';
247 do_init() and do_stop_all() if $opt_action eq 'stop_all';
248 do_init() and do_stop_all() and do_start_all() if $opt_action eq 'restart_all';
249
250