~ubuntu-branches/ubuntu/quantal/haproxy/quantal

« back to all changes in this revision

Viewing changes to examples/check

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2007-08-17 09:33:41 UTC
  • Revision ID: james.westby@ubuntu.com-20070817093341-h0t6aeeoyzo25z3r
Tags: upstream-1.3.12.dfsg
ImportĀ upstreamĀ versionĀ 1.3.12.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/perl
 
2
###################################################################################################################
 
3
# $Id:: check 20 2007-02-23 14:26:44Z fabrice                     $
 
4
# $Revision:: 20                                                  $
 
5
###################################################################################################################
 
6
# Authors : Fabrice Dulaunoy <fabrice@dulaunoy.com>
 
7
#
 
8
# Copyright (C) 2006-2007 Fabrice Dulaunoy <fabrice@dulaunoy.com>
 
9
#
 
10
# This program is free software; you can redistribute it and/or modify it
 
11
# under the terms of the GNU General Public License as published by the
 
12
# Free Software Foundation; either version 2 of the License, or (at your
 
13
# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
 
14
#
 
15
# This program is distributed in the hope that it will be useful, but
 
16
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
17
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
18
# for more details.
 
19
###################################################################################################################
 
20
#
 
21
###################################################################################################################
 
22
 
 
23
use strict;
 
24
 
 
25
package MyPackage;
 
26
use Config::General;
 
27
use Getopt::Std;
 
28
use LWP::UserAgent;
 
29
use URI;
 
30
use File::Basename;
 
31
 
 
32
# CVS VSERSION
 
33
#my $VERSION = do { my @rev = ( q$Revision: 20 $ =~ /\d+/g ); sprintf "%d." . "%d" x $#rev, @rev };
 
34
# SVN VERSION
 
35
my $VERSION = sprintf "1.%02d", '$Revision: 20 $ ' =~ /(\d+)/;
 
36
 
 
37
my %option;
 
38
 
 
39
getopts( "vHhc:", \%option );
 
40
 
 
41
if ( $option{ h } )
 
42
{
 
43
    print "Usage: $0 [options ...]\n\n";
 
44
    print "Where options include:\n";
 
45
    print "\t -h \t\t\tthis help (what else ?)\n";
 
46
    print "\t -H \t\t\tshow a sample config file\n";
 
47
    print "\t -v \t\t\tprint version and exit\n";
 
48
    print "\t -c file \t\tuse config file (default /etc/check.conf)\n";
 
49
    print "\n\t This is a small program parsing the config file \n";
 
50
    print "\t and checking one or more condition on one or more  servers\n";
 
51
    print "\t these condition could be \n";
 
52
    print "\t\t HTTP return code list (with optinal Host Header and optional Basic Authentication) \n";
 
53
    print "\t\t a regex over a HTTP GET  (with optinal Host Header and optional Basic Authentication)\n";
 
54
    print "\t\t a regex over a FTP GET ( with optional Basic Authentication)\n";
 
55
    print "\t\t a TCP open port\n";
 
56
    print "\t the result state is an AND over all tests  \n";
 
57
    print "\t this result could be \n";
 
58
    print "\t\t a simple HTTP return state  (\"200 OK\" or \"503 Service Unavailable\"  \n";
 
59
    print "\t\t a HTML page with a status OK or NOK for each test\n";
 
60
    print "\t\t a HTML page with a staus OK or NOK for each test in a row of a TABLE\n";
 
61
    print "\n\t The natural complement of this tools is the poll_check tool\n";
 
62
    print "\t The result code of this tools is designed to fit the HAPROXY requirement (test over a port not related to the WEB server)\n";
 
63
}
 
64
 
 
65
if ( $option{ H } )
 
66
{
 
67
    print "\t A sample config file could be:\n";
 
68
    print <<'EOF';
 
69
    
 
70
                        ###########################################################
 
71
                        # listening port ( default 9898 )
 
72
                        port 9899
 
73
                        
 
74
                        # on which IP to bind (default 127.0.0.1 ) * = all IP
 
75
                        host 10.2.1.1
 
76
                        
 
77
                        # which client addr is allow ( default 127.0.0.0/8 )
 
78
                        #cidr_allow = 0.0.0.0/0 
 
79
                        
 
80
                        # verbosity from 0 to 4 (default 0 = no log )
 
81
                        log_level = 1
 
82
                        
 
83
                        # daemonize (default 0 = no )
 
84
                        daemon = 1
 
85
                        
 
86
                        # content put a HTML content after header
 
87
                        # (default 0 = no content 1 = html 2 = table )
 
88
                        content = 2
 
89
                        
 
90
                        # reparse the config file at each request ( default 0 = no )
 
91
                        # only SIGHUP reread the config file)
 
92
                        reparse = 1
 
93
                        
 
94
                        # pid_file  (default /var/run/check.pid )
 
95
                        # $$$ = basename of config file
 
96
                        # $$ = PID
 
97
                        pid_file=/var/run/CHECK_$$$.pid
 
98
                        
 
99
                        # log_file  (default /var/log/check.log )
 
100
                        # $$$ = basename of config file
 
101
                        # $$ = PID
 
102
                        log_file=/var/log/CHECK_$$$.log
 
103
                        
 
104
                        # number of servers to keep running (default = 5)
 
105
                        min_servers = 2
 
106
                        
 
107
                        # number of servers to have waiting for requests (default = 2)
 
108
                        min_spare_servers = 1
 
109
                        
 
110
                        # maximum number of servers to have waiting for requests (default = 10)
 
111
                        max_spare_servers =1
 
112
                        
 
113
                        # number of servers (default = 50)
 
114
                        max_servers = 2
 
115
                        
 
116
                        
 
117
                        ###########################################################
 
118
                        # a server to check
 
119
                        # type could be get , regex or tcp
 
120
                        #
 
121
                        # get = do a http or ftp get and check the result code with
 
122
                        # the list, coma separated, provided ( default = 200,201 )
 
123
                        # hostheader is optional and send to the server if provided
 
124
                        #
 
125
                        # regex = do a http or ftp get and check the content result 
 
126
                        # with regex provided
 
127
                        # hostheader is optional and send to the server if provided
 
128
                        #
 
129
                        # tcp = test if the tcp port provided is open
 
130
                        #
 
131
                        ###########################################################
 
132
                        
 
133
                        <realserver>
 
134
                                url=http://127.0.0.1:80/apache2-default/index.html
 
135
                                type = get
 
136
                                code=200,201
 
137
                                hostheader = www.test.com
 
138
                        </realserver>
 
139
                        
 
140
                        
 
141
                        <realserver>
 
142
                                url=http://127.0.0.1:82/apache2-default/index.html
 
143
                                type = get
 
144
                                code=200,201
 
145
                                hostheader = www.myhost.com
 
146
                        </realserver>
 
147
                        
 
148
                        <realserver>
 
149
                                url=     http://10.2.2.1
 
150
                                type = regex
 
151
                                regex= /qdAbm/
 
152
                        </realserver>
 
153
                        
 
154
                        <realserver>
 
155
                                type = tcp
 
156
                                url = 10.2.2.1
 
157
                                port =80
 
158
                        </realserver>
 
159
                        
 
160
                        <realserver>
 
161
                                type = get
 
162
                                url = ftp://USER:PASSWORD@10.2.3.1
 
163
                                code=200,201
 
164
                        </realserver>
 
165
                        ###########################################################
 
166
 
 
167
 
 
168
 
 
169
EOF
 
170
 
 
171
}
 
172
 
 
173
if ( $option{ h } || $option{ H } )
 
174
{
 
175
    exit;
 
176
}
 
177
 
 
178
if ( $option{ v } ) { print "$VERSION\n"; exit; }
 
179
 
 
180
use vars qw(@ISA);
 
181
use Net::Server::PreFork;
 
182
@ISA = qw(Net::Server::PreFork);
 
183
 
 
184
my $port;
 
185
my $host;
 
186
my $reparse;
 
187
my $cidr_allow;
 
188
my $log_level;
 
189
my $log_file;
 
190
my $pid_file;
 
191
my $daemon;
 
192
my $min_servers;
 
193
my $min_spare_servers;
 
194
my $max_spare_servers;
 
195
my $max_servers;
 
196
my $html_content;
 
197
 
 
198
my $conf_file = $option{ c } || "/etc/check.conf";
 
199
my $pwd = $ENV{ PWD };
 
200
$conf_file =~ s/^\./$pwd/;
 
201
$conf_file =~ s/^([^\/])/$pwd\/$1/;
 
202
my $basename = basename( $conf_file, ( '.conf' ) );
 
203
my $CONF = parse_conf( $conf_file );
 
204
 
 
205
my $reparse_one = 0;
 
206
 
 
207
$SIG{ HUP } = sub { $reparse_one = 1; };
 
208
 
 
209
my @TEST;
 
210
my $test_list = $CONF->{ realserver };
 
211
if ( ref( $test_list ) eq "ARRAY" )
 
212
{
 
213
    @TEST = @{ $test_list };
 
214
}
 
215
else
 
216
{
 
217
    @TEST = ( $test_list );
 
218
}
 
219
 
 
220
my $server = MyPackage->new(
 
221
    {
 
222
        port                => $port,
 
223
        host                => $host,
 
224
        cidr_allow          => $cidr_allow,
 
225
        log_level           => $log_level,
 
226
        child_communication => 1,
 
227
        setsid              => $daemon,
 
228
        log_file            => $log_file,
 
229
        pid_file            => $pid_file,
 
230
        min_servers         => $min_servers,
 
231
        min_spare_servers   => $min_spare_servers,
 
232
        max_spare_servers   => $max_spare_servers,
 
233
        max_servers         => $max_servers,
 
234
    }
 
235
);
 
236
 
 
237
$server->run();
 
238
exit;
 
239
 
 
240
sub process_request
 
241
{
 
242
    my $self = shift;
 
243
    if ( $reparse || $reparse_one )
 
244
    {
 
245
        $CONF = parse_conf( $conf_file );
 
246
    }
 
247
    my $result;
 
248
    my @TEST;
 
249
    my $test_list = $CONF->{ realserver };
 
250
 
 
251
    if ( ref( $test_list ) eq "ARRAY" )
 
252
    {
 
253
        @TEST = @{ $test_list };
 
254
    }
 
255
    else
 
256
    {
 
257
        @TEST = ( $test_list );
 
258
    }
 
259
 
 
260
    my $allow_code;
 
261
    my $test_item;
 
262
    my $html_data;
 
263
    foreach my $test ( @TEST )
 
264
    {
 
265
        my $uri;
 
266
        my $authority;
 
267
        my $URL = $test->{ url };
 
268
        $uri       = URI->new( $URL );
 
269
        $authority = $uri->authority;
 
270
 
 
271
        if ( exists $test->{ type } )
 
272
        {
 
273
            if ( $test->{ type } =~ /get/i )
 
274
            {
 
275
                my $allow_code = $test->{ code } || '200,201';
 
276
                $test_item++;
 
277
                my $host = $test->{ hostheader } || $authority;
 
278
                my $res = get( $URL, $allow_code, $host );
 
279
                if ( $html_content == 1 )
 
280
                {
 
281
                    if ( $res )
 
282
                    {
 
283
                        $html_data .= "GET OK $URL<br>\r\n";
 
284
                    }
 
285
                    else
 
286
                    {
 
287
                        $html_data .= "GET NOK $URL<br>\r\n";
 
288
                    }
 
289
                }
 
290
                if ( $html_content == 2 )
 
291
                {
 
292
                    if ( $res )
 
293
                    {
 
294
                        $html_data .= "<tr><td>GET</td><td>OK</td><td>$URL</td></tr>\r\n";
 
295
                    }
 
296
                    else
 
297
                    {
 
298
                        $html_data .= "<tr><td>GET</td><td>NOK</td><td>$URL</td></tr>\r\n";
 
299
                    }
 
300
                }
 
301
                $result += $res;
 
302
            }
 
303
            if ( $test->{ type } =~ /regex/i )
 
304
            {
 
305
                my $regex = $test->{ regex };
 
306
                $test_item++;
 
307
                my $host = $test->{ hostheader } || $authority;
 
308
                my $res = regex( $URL, $regex, $host );
 
309
                if ( $html_content == 1 )
 
310
                {
 
311
                    if ( $res )
 
312
                    {
 
313
                        $html_data .= "REGEX OK $URL<br>\r\n";
 
314
                    }
 
315
                    else
 
316
                    {
 
317
                        $html_data .= "REGEX NOK $URL<br>\r\n";
 
318
                    }
 
319
                }
 
320
                if ( $html_content == 2 )
 
321
                {
 
322
                    if ( $res )
 
323
                    {
 
324
                        $html_data .= "<tr><td>REGEX</td><td>OK</td><td>$URL</td></tr>\r\n";
 
325
                    }
 
326
                    else
 
327
                    {
 
328
                        $html_data .= "<tr><td>REGEX</td><td>NOK</td><td>$URL</td></tr>\r\n";
 
329
                    }
 
330
                }
 
331
                $result += $res;
 
332
            }
 
333
            if ( $test->{ type } =~ /tcp/i )
 
334
            {
 
335
                $test_item++;
 
336
                my $PORT = $test->{ port } || 80;
 
337
                my $res = TCP( $URL, $PORT );
 
338
                if ( $html_content == 1 )
 
339
                {
 
340
                    if ( $res )
 
341
                    {
 
342
                        $html_data .= "TCP OK  $URL<br>\r\n";
 
343
                    }
 
344
                    else
 
345
                    {
 
346
                        $html_data .= "TCP NOK $URL<br>\r\n";
 
347
                    }
 
348
                }
 
349
                if ( $html_content == 2 )
 
350
                {
 
351
                    if ( $res )
 
352
                    {
 
353
                        $html_data .= "<tr><td>TCP</td><td>OK</td><td>$URL</td></tr>\r\n";
 
354
                    }
 
355
                    else
 
356
                    {
 
357
                        $html_data .= "<tr><td>TCP</td><td>NOK</td><td>$URL</td></tr>\r\n";
 
358
                    }
 
359
                }
 
360
                $result += $res;
 
361
            }
 
362
        }
 
363
    }
 
364
 
 
365
    my $len;
 
366
    if ( $html_content == 1 )
 
367
    {
 
368
        $html_data = "\r\n<html><body>\r\n$html_data</body></html>\r\n";
 
369
        $len       = ( length( $html_data ) ) - 2;
 
370
    }
 
371
    if ( $html_content == 2 )
 
372
    {
 
373
        $html_data = "\r\n<table align='center' border='1' >\r\n$html_data</table>\r\n";
 
374
        $len       = ( length( $html_data ) ) - 2;
 
375
    }
 
376
 
 
377
    if ( $result != $test_item )
 
378
    {
 
379
        my $header = "HTTP/1.0 503 Service Unavailable\r\n";
 
380
        if ( $html_content )
 
381
        {
 
382
            $header .= "Content-Length: $len\r\nContent-Type: text/html; charset=iso-8859-1\r\n";
 
383
        }
 
384
        print $header . $html_data;
 
385
        return;
 
386
    }
 
387
    my $header = "HTTP/1.0 200 OK\r\n";
 
388
    if ( $html_content )
 
389
    {
 
390
        $header .= "Content-Length: $len\r\nContent-Type: text/html; charset=iso-8859-1\r\n";
 
391
    }
 
392
    print $header. $html_data;
 
393
}
 
394
 
 
395
1;
 
396
 
 
397
##########################################################
 
398
##########################################################
 
399
# function to REGEX on a GET from URL
 
400
#       arg:    uri
 
401
#               regex to test (with extra parameter like perl e.g.  /\bweb\d{2,3}/i )
 
402
#               IP
 
403
#               port (optionnal: default=80)
 
404
#       ret:    0 if no reply
 
405
#               1 if reply
 
406
##########################################################
 
407
##########################################################
 
408
sub regex
 
409
{
 
410
    my $url   = shift;
 
411
    my $regex = shift;
 
412
    my $host  = shift;
 
413
 
 
414
    $regex =~ /\/(.*)\/(.*)/;
 
415
    my $reg = $1;
 
416
    my $ext = $2;
 
417
    my %options;
 
418
    $options{ 'agent' }   = "LB_REGEX_PROBE/$VERSION";
 
419
    $options{ 'timeout' } = 10;
 
420
    my $ua = LWP::UserAgent->new( %options );
 
421
    my $response = $ua->get( $url, "Host" => $host );
 
422
    if ( $response->is_success )
 
423
    {
 
424
        my $html = $response->content;
 
425
        if ( $ext =~ /i/ )
 
426
        {
 
427
            if ( $html =~ /$reg/si )
 
428
            {
 
429
                return 1;
 
430
            }
 
431
        }
 
432
        else
 
433
        {
 
434
            if ( $html =~ /$reg/s )
 
435
            {
 
436
                return 1;
 
437
            }
 
438
        }
 
439
    }
 
440
    return 0;
 
441
}
 
442
 
 
443
##########################################################
 
444
##########################################################
 
445
# function to GET an URL (HTTP or FTP) ftp://FTPTest:6ccount4F@brice!@172.29.0.146
 
446
#       arg:    uri
 
447
#               allowed code (comma seaparated)
 
448
#               IP
 
449
#               port (optionnal: default=80)
 
450
#       ret:    0 if not the expected vcode
 
451
#               1 if the expected code is returned
 
452
##########################################################
 
453
##########################################################
 
454
sub get
 
455
{
 
456
    my $url  = shift;
 
457
    my $code = shift;
 
458
    my $host = shift;
 
459
 
 
460
    $code =~ s/\s*//g;
 
461
    my %codes = map { $_ => $_ } split /,/, $code;
 
462
    my %options;
 
463
    $options{ 'agent' }   = "LB_HTTP_PROBE/$VERSION";
 
464
    $options{ 'timeout' } = 10;
 
465
    my $ua = LWP::UserAgent->new( %options );
 
466
    my $response = $ua->get( $url, "Host" => $host );
 
467
    if ( $response->is_success )
 
468
    {
 
469
        my $rc = $response->{ _rc };
 
470
        if ( defined $codes{ $rc } )
 
471
        {
 
472
            return 1;
 
473
        }
 
474
    }
 
475
    return 0;
 
476
}
 
477
 
 
478
##########################################################
 
479
##########################################################
 
480
# function to test a port on a host
 
481
#       arg:    hostip
 
482
#               port
 
483
#               timeout
 
484
#       ret:    0 if not open
 
485
#               1 if open
 
486
##########################################################
 
487
##########################################################
 
488
sub TCP
 
489
{
 
490
    use IO::Socket::PortState qw(check_ports);
 
491
    my $remote_host = shift;
 
492
    my $remote_port = shift;
 
493
    my $timeout     = shift;
 
494
 
 
495
    my %porthash = ( tcp => { $remote_port => { name => 'to_test', } } );
 
496
    check_ports( $remote_host, $timeout, \%porthash );
 
497
    return $porthash{ tcp }{ $remote_port }{ open };
 
498
}
 
499
 
 
500
##############################################
 
501
# parse config file
 
502
# IN:   File PATH
 
503
# Out:  Ref to a hash with config data
 
504
##############################################
 
505
sub parse_conf
 
506
{
 
507
    my $file = shift;
 
508
 
 
509
    my $conf = new Config::General(
 
510
        -ConfigFile        => $file,
 
511
        -ExtendedAccess    => 1,
 
512
        -AllowMultiOptions => "yes"
 
513
    );
 
514
    my %config = $conf->getall;
 
515
    $port              = $config{ port }              || 9898;
 
516
    $host              = $config{ host }              || '127.0.0.1';
 
517
    $reparse           = $config{ reparse }           || 0;
 
518
    $cidr_allow        = $config{ cidr_allow }        || '127.0.0.0/8';
 
519
    $log_level         = $config{ log_level }         || 0;
 
520
    $log_file          = $config{ log_file }          || "/var/log/check.log";
 
521
    $pid_file          = $config{ pid_file }          || "/var/run/check.pid";
 
522
    $daemon            = $config{ daemon }            || 0;
 
523
    $min_servers       = $config{ min_servers }       || 5;
 
524
    $min_spare_servers = $config{ min_spare_servers } || 2;
 
525
    $max_spare_servers = $config{ max_spare_servers } || 10;
 
526
    $max_servers       = $config{ max_servers }       || 50;
 
527
    $html_content      = $config{ content }           || 0;
 
528
 
 
529
    $pid_file =~ s/\$\$\$/$basename/g;
 
530
    $pid_file =~ s/\$\$/$$/g;
 
531
    $log_file =~ s/\$\$\$/$basename/g;
 
532
    $log_file =~ s/\$\$/$$/g;
 
533
 
 
534
    if ( !( keys %{ $config{ realserver } } ) )
 
535
    {
 
536
        die "No farm to test\n";
 
537
    }
 
538
    return ( \%config );
 
539
}
 
540