File Coverage

blib/lib/Nginx/Control.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Nginx::Control;
2 2     2   313954 use Moose;
  0            
  0            
3             use MooseX::Types::Path::Class;
4             use Path::Class;
5              
6             our $VERSION = '0.04';
7             our $AUTHORITY = 'cpan:PERIGRIN';
8             our $NGINX_BIN = 'nginx';
9             our @SEARCH_PATH = qw( /usr /usr/local /usr/local/nginx /opt/local /opt/nginx /sw );
10              
11             has 'config_file' => (
12             is => 'rw',
13             isa => 'Path::Class::File',
14             coerce => 1,
15             );
16              
17             has 'prefix_path' => (
18             is => 'rw',
19             isa => 'Path::Class::Dir',
20             coerce => 1,
21             );
22              
23             has 'binary_path' => (
24             is => 'rw',
25             isa => 'Path::Class::File',
26             coerce => 1,
27             lazy => 1,
28             builder => '_find_binary_path'
29             );
30              
31             has 'pid_file' => (
32             is => 'rw',
33             isa => 'Path::Class::File',
34             coerce => 1,
35             lazy => 1,
36             builder => '_find_pid_file',
37             );
38              
39             has 'server_pid' => (
40             init_arg => undef,
41             is => 'ro',
42             isa => 'Int',
43             lazy => 1,
44             builder => '_find_server_pid',
45             );
46              
47             sub log { shift; warn @_, "\n" }
48              
49             ## ---------------------------------
50             ## events
51              
52             sub pre_startup { inner() }
53             sub post_startup { inner() }
54              
55             sub pre_shutdown { inner() }
56             sub post_shutdown { inner() }
57              
58             sub pre_reload { inner() }
59             sub post_reload { inner() }
60              
61             ## ---------------------------------
62              
63             sub _find_server_pid {
64             my $self = shift;
65             my $pid = $self->pid_file->slurp( chomp => 1 );
66             ($pid)
67             || confess "No PID found in pid_file (" . $self->pid_file . ")";
68             $pid;
69             }
70              
71             sub _find_pid_file {
72             my $self = shift;
73              
74             my $config_file = $self->config_file;
75              
76             ( -f $config_file )
77             || confess
78             "Could not find pid_file because could not find config file ($config_file)";
79              
80             # the two possible approaches to
81             # find the pid file (that I know of)
82             my @approaches = ( sub { $config_file->slurp( chomp => 1 ) }, );
83              
84             foreach my $approach (@approaches) {
85             my @config = $approach->();
86             foreach my $line (@config) {
87             if ( $line =~ /^\s*pid\s+(.*);/ ) {
88             return Path::Class::File->new($1);
89             }
90             }
91             }
92              
93             confess
94             "Could not locate the pid-file information, please supply it manually";
95             }
96              
97             sub _find_binary_path {
98             my $self = shift;
99              
100             my $nginx = do {
101             my $bin = `which $NGINX_BIN`;
102             chomp($bin);
103             Path::Class::File->new($bin);
104             };
105              
106             return $nginx if -x $nginx;
107              
108             for my $prefix (@SEARCH_PATH) {
109             for my $bindir (qw(bin sbin)) {
110             my $nginx = Path::Class::File->new( $prefix, $bindir, $NGINX_BIN );
111             return $nginx if -x $nginx;
112             }
113             }
114              
115             confess "can't find nginx anywhere tried => ("
116             . ( $nginx || 'nothing' ) . ")";
117             }
118              
119             sub _construct_command_line {
120             my $self = shift;
121             my @opts = @_;
122             my $conf = $self->config_file;
123              
124             ( -f $conf )
125             || confess "Could not locate configuration file ($conf)";
126              
127             my @cli = ( $self->binary_path, @opts, '-c', $conf->stringify );
128             if ($self->prefix_path) {
129             push @cli, ( '-p', $self->prefix_path->stringify . "/" );
130             }
131              
132             return @cli;
133             }
134              
135             ## ---------------------------------
136              
137             sub is_server_running {
138             my $self = shift;
139              
140             # no pid file, no server running ...
141             return 0 unless -s $self->pid_file;
142              
143             # has pid file, then check it ...
144             kill( 0, $self->server_pid ) ? 1 : 0;
145             }
146              
147             sub start {
148             my $self = shift;
149              
150             $self->log("Starting nginx ...");
151             $self->pre_startup;
152              
153             # NOTE:
154             # do this after startup so that it
155             # would be possible to write the
156             # config file in the pre_startup
157             # hook if we wanted to.
158             # - SL
159             my @cli = $self->_construct_command_line;
160             $self->log( "Command-line: " . join(" ", @cli) );
161              
162             unless ( system(@cli) == 0 ) {
163             $self->log("Could not start nginx (@cli) exited with status $?");
164             return;
165             }
166              
167             $self->post_startup;
168             $self->log("Nginx started.");
169             }
170              
171             sub stop {
172             my $self = shift;
173             my $pid_file = $self->pid_file;
174              
175             if ( -f $pid_file ) {
176              
177             if ( !$self->is_server_running ) {
178             $self->log(
179             "Found pid_file($pid_file), but process does not seem to be running."
180             );
181             return;
182             }
183              
184             $self->log("Stoping nginx ...");
185             $self->pre_shutdown;
186              
187             my @cli = $self->_construct_command_line(qw( -s stop ));
188             unless ( system(@cli) == 0 ) {
189             kill 2, $self->server_pid;
190             }
191              
192             $self->post_shutdown;
193             $self->log("Nginx stopped.");
194              
195             return;
196             }
197              
198             $self->log("... pid_file($pid_file) not found.");
199             }
200              
201             sub reload {
202             my $self = shift;
203             my $pid_file = $self->pid_file;
204              
205             unless ( -f $pid_file ) {
206             $self->log("... pid_file($pid_file) not found.");
207             }
208              
209             unless ( $self->is_server_running ) {
210             $self->log(
211             "Found pid_file($pid_file), but process does not seem to be running."
212             );
213             return;
214             }
215              
216             $self->log("Reloading nginx ...");
217             $self->pre_reload;
218              
219             my @cli = $self->_construct_command_line(qw( -s reload ));
220             unless ( system(@cli) == 0 ) {
221             $self->log("Failed to reload Nginx.");
222             }
223              
224             $self->post_reload;
225             $self->log("Nginx reloaded.");
226             }
227              
228             sub test {
229             my $self = shift;
230             my $pid_file = $self->pid_file;
231              
232             my @cli = $self->_construct_command_line("-t");
233              
234             return ( system(@cli) == 0 );
235             }
236              
237             no Moose;
238             1;
239              
240             __END__
241              
242             =pod
243              
244             =head1 NAME
245              
246             Nginx::Control - Simple class to manage a Nginx server
247              
248             =head1 SYNOPSIS
249              
250             #!perl
251            
252             use strict;
253             use warnings;
254            
255             use Nginx::Control;
256            
257             my ($command) = @ARGV;
258            
259             my $ctl = Nginx::Control->new(
260             config_file => [qw[ conf nginx.conf ]],
261             # PID file can also be discovered automatically
262             # from the conf, or if you prefer you can specify
263             pid_file => 'nginx.control.pid',
264             );
265            
266             if ($ctl->test) {
267             $ctl->start if lc($command) eq 'start';
268             $ctl->stop if lc($command) eq 'stop';
269             }
270              
271             =head1 DESCRIPTION
272              
273             This is a fork of L<Lighttpd::Control> to work with Nginx, it maintains 100%
274             API compatibility. In fact most of this documentation was stolen too. This is
275             an early release with only the bare bones functionality needed, future
276             releases will surely include more functionality. Suggestions and crazy ideas
277             welcomed, especially in the form of patches with tests.
278              
279             =head1 ATTRIBUTES
280              
281             =over 4
282              
283             =item I<config_file>
284              
285             This is a L<Path::Class::File> instance for the configuration file.
286              
287             =item I<prefix_path>
288              
289             This is an optional L<Path::Class::Dir> instance pointing to the
290             root prefix path where you would like Nginx to be started from.
291             This will typically point at a location where logs and other sorts
292             of files will be stored at start-up time.
293              
294             =item I<binary_path>
295              
296             This is a L<Path::Class::File> instance pointing to the Nginx
297             binary. This can be autodiscovered or you can specify it via the
298             constructor.
299              
300             =item I<pid_file>
301              
302             This is a L<Path::Class::File> instance pointing to the Nginx
303             pid file. This can be autodiscovered from the config file or you
304             can specify it via the constructor.
305              
306             =item I<server_pid>
307              
308             This is the PID of the live server.
309              
310             =back
311              
312             =head1 METHODS
313              
314             =over 4
315              
316             =item B<start>
317              
318             Starts the Nginx server that is currently being controlled by this
319             instance. It will also run the pre_startup and post_startup hooks.
320              
321             =item B<stop>
322              
323             Stops the Nginx server that is currently being controlled by this
324             instance. It will also run the pre_shutdown and post_shutdown hooks.
325              
326             It will attempt to send a signal to the running master Nginx process
327             to stop cleanly, and if this fails will manually kill the process.
328              
329             =item B<reload>
330              
331             Reloads the Nginx server configuration without stopping and starting
332             the process. This ensures a minimal amount of downtime will occur
333             while updating to a new configuration.
334              
335             =item B<test>
336              
337             Tests the Nginx server config to make sure it can start successfully.
338              
339             =item B<is_server_running>
340              
341             Checks to see if the Nginx server that is currently being controlled
342             by this instance is running or not (based on the state of the PID file).
343              
344             =item B<log>
345              
346             Simple logger that you can use, it just sends the output to STDERR via
347             the C<warn> function.
348              
349             =back
350              
351             =head1 AUGMENTABLE METHODS
352              
353             These methods can be augmented in a subclass to add extra functionality
354             to your control script. Here is an example of how they might be used
355             to integrate with L<FCGI::Engine::Manager> (For a complete, working
356             version of this, take a look at the file F<003_basic_with_fcgi_engine.t>
357             in the test suite).
358              
359             package My::Nginx::Control;
360             use Moose;
361            
362             extends 'Nginx::Control';
363            
364             has 'fcgi_manager' => (
365             is => 'ro',
366             isa => 'FCGI::Engine::Manager',
367             default => sub {
368             FCGI::Engine::Manager->new(
369             conf => 'conf/fcgi.engine.yml'
370             )
371             },
372             );
373            
374             augment post_startup => sub {
375             my $self = shift;
376             $self->log('Starting the FCGI Engine Manager ...');
377             $self->fcgi_manager->start;
378             };
379            
380             augment post_shutdown => sub {
381             my $self = shift;
382             $self->log('Stopping the FCGI Engine Manager ...');
383             $self->fcgi_manager->stop;
384             };
385              
386             =over 4
387              
388             =item B<pre_startup>
389              
390             =item B<post_startup>
391              
392             =item B<pre_shutdown>
393              
394             =item B<post_shutdown>
395              
396             =item B<pre_reload>
397              
398             =item B<post_reload>
399              
400             =back
401              
402             =head1 BUGS
403              
404             All complex software has bugs lurking in it, and this module is no
405             exception. If you find a bug please either email me, or add the bug
406             to cpan-RT.
407              
408             =head1 AUTHOR
409              
410             Chris Prather E<lt>chris@prather.org$<gt>
411              
412             Based on L<Lighttpd::Control> by Stevan Little E<lt>stevan.little@iinteractive.comE<gt>
413              
414             =head1 COPYRIGHT AND LICENSE
415              
416             Copyright 2008 Chris Prather
417              
418             except for those parts that are
419              
420             Copyright 2008 Infinity Interactive, Inc.
421              
422             L<http://www.iinteractive.com>
423              
424             This library is free software; you can redistribute it and/or modify
425             it under the same terms as Perl itself.
426              
427             =cut