Subversion Repositories sysadmin_scripts

Rev

Rev 93 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
88 rodolico 1
#! /usr/bin/env perl
2
 
3
use strict;
4
use warnings;
5
 
89 rodolico 6
# Currently three types of tests
7
# type: lwp
8
# url: site to test
9
# timeout: optional integer, number of seconds. defaults to 'default timeout'
10
#
11
# type: ping
12
# url: site to test
13
# timeout: optional integer, number of seconds. defaults to 'default timeout'
14
#
15
# type: netcat
16
# url: site to test
17
# port: port to test on
18
# timeout: optional integer, number of seconds. defaults to 'default timeout'
93 rodolico 19
# additional parameters: any additional cli parameters to add.
89 rodolico 20
 
93 rodolico 21
 
88 rodolico 22
use Data::Dumper;
89 rodolico 23
use FindBin;
24
use File::Spec;
88 rodolico 25
 
89 rodolico 26
# name of script directory, no trailing slash
27
my $MY_DIR = $FindBin::Bin;
28
# name of currently executing file
29
my $MY_NAME = $FindBin::Script;
88 rodolico 30
 
89 rodolico 31
my $configName = $MY_DIR . '/' . $MY_NAME . '.yaml';
32
 
33
# hashref which holds configuration
34
my $config;
35
 
36
# simply read the contents of YAML file $filename into
37
# hashref and return the hashref
88 rodolico 38
sub loadConf {
89 rodolico 39
   use YAML::Tiny;
40
   my $filename = shift;
41
   my $conf = YAML::Tiny->read( $filename );
42
   return $conf->[0];
88 rodolico 43
}
44
 
89 rodolico 45
# not used. May use it later, who knows.
46
sub saveConf {
47
   use YAML::Tiny;
48
   my ( $filename, $config ) = @_;
49
   my $yaml = YAML::Tiny->new( $config );
50
   $yaml->write( $filename );
51
}
88 rodolico 52
 
89 rodolico 53
# check using netcat
54
sub checkNetCat {
93 rodolico 55
   my ($url, $port, $timeout, $additionalParameters ) = @_;
89 rodolico 56
   my $netcat = `which nc`;
57
   chomp $netcat;
58
   unless ( $netcat ) {
59
      warn "Netcat not found, not testing\n";
60
      return 0;
61
   }
93 rodolico 62
   $netcat = join( ' ', ($netcat, "-z -w $timeout", $additionalParameters, $url, $port ) );
94 rodolico 63
   print "\t$netcat\n" if $config->{'TESTING'};
89 rodolico 64
   `$netcat`;
65
   return not $? >> 8;
88 rodolico 66
} 
67
 
89 rodolico 68
# this has only been tested on http and https, but with a little work
69
# could do echo, ftp
70
# will NOT work with some WordPress sites since it goes into
71
# infinite redirect loop
88 rodolico 72
sub checkHTTP {
89 rodolico 73
   use LWP::UserAgent; # probably should eval this in case not loaded
88 rodolico 74
   my ($url, $timeout) = @_;
89 rodolico 75
   # just getting HEAD, so small amount of data
88 rodolico 76
   my $r = HTTP::Request->new( 'HEAD', $url );
89 rodolico 77
   # new agent, make the request, return success
88 rodolico 78
   my $ua = LWP::UserAgent->new();
79
   my $res = $ua->request($r);
80
   return $res->is_success;
81
}
82
 
89 rodolico 83
# we're only using icmp. Probably could extend to other things, but
84
# netcat and lwp do them also, I think.
85
# basically a ping. Must be run as root.
88 rodolico 86
sub checkPing {
87
   my ($url,$type,$timeout) = @_;
88
   use Net::Ping;
89 rodolico 89
   # verify running as root
90
   my $login = (getpwuid $>);
91
   if ( $login ne 'root' ) {
92
      warn "This script must be run as root for ping type\n";
93
      return 0;
94
   }
95
 
88 rodolico 96
   my $p = Net::Ping->new('icmp');
97
   return $p->ping( $url ) ? 1 : 0;
98
}   
99
 
89 rodolico 100
# determines which test to run, runs it and returns results
88 rodolico 101
sub runTest {
102
   my $parameters = shift;
89 rodolico 103
   #die Dumper( $parameters );
88 rodolico 104
   my $result;
105
   if ( $parameters->{'type'} eq 'lwp' ) {
89 rodolico 106
      $result = &checkHTTP( $parameters->{'url'}, $parameters->{'timeout'} );
88 rodolico 107
   } elsif ( $parameters->{'type'} eq 'ping' ) {
89 rodolico 108
      $result = checkPing( $parameters->{'url'}, $parameters->{'timeout'} );
109
   } elsif ( $parameters->{'type'} eq 'netcat' ) {
93 rodolico 110
      $result = checkNetCat( 
111
               $parameters->{'url'},
112
               $parameters->{'port'},
113
               $parameters->{'timeout'}, 
114
               defined $parameters->{'additional parameters'} ? $parameters->{'additional parameters'} : '' 
115
               );
89 rodolico 116
   } else {
91 rodolico 117
      warn "Unknown test type $parameters->{type}, aborting test\n";
89 rodolico 118
      $result = 0;
88 rodolico 119
   }
120
   return $result;
121
}
122
 
89 rodolico 123
# just make up the flag file name in one place so we don't
124
# forget to do it everyplace it is needed
125
sub flagFileName {
126
   my $name = shift;
127
   return "/tmp/$name.down";
128
}
88 rodolico 129
 
91 rodolico 130
# Report outage via system mail
131
# your system must be able to send e-mail from 'report from'
132
# otherwise, you'll need to use something like sendemail.pl
92 rodolico 133
# apt install libemail-sender-perl libemail-mime-perl
91 rodolico 134
sub reportViaMail {
135
   my ( $name,$parameters ) = @_;
136
   use Email::MIME;
137
   my $message = Email::MIME->create(
138
     header_str => [
139
       From    => $parameters->{'report from'},
140
       To      => $parameters->{'report to'},
141
       Subject => "Outage on $name",
142
     ],
143
     attributes => {
144
       encoding => 'quoted-printable',
145
       charset  => 'ISO-8859-1',
146
     },
147
     body_str => "$name has been reported as current state down\n",
148
   );
149
 
150
   # send the message
151
   use Email::Sender::Simple qw(sendmail);
152
   sendmail($message);   
153
}   
154
 
90 rodolico 155
# report the outage
156
sub reportOutage {
157
   my ( $name,$parameters ) = @_;
91 rodolico 158
   if ( $parameters->{'report type'} eq 'mail' ) {
159
      &reportViaMail( $name,$parameters );
160
   } else {
161
      warn "Do not have a way of notifying outage for $name\n";
162
   }
90 rodolico 163
}
164
 
89 rodolico 165
# this will put a flag file in /tmp/monitorNetwork which will control
166
# countdown in case of failure
167
# if the countdown is exceeded, it will report the status 
168
sub processFailure {
169
   my ( $name, $parameters ) = @_;
90 rodolico 170
   # temporary for testing
92 rodolico 171
   my $flagFileName = &flagFileName( $name );
90 rodolico 172
   my $remainingCounts = $parameters->{'failure count'};
94 rodolico 173
   print "$name => Failed\n" if $config->{'TESTING'};
90 rodolico 174
   if ( -f $flagFileName ) {
175
      # open flag file, read the value into $remaingCounts
176
      return if $remainingCounts == -1;
177
   }
178
   if ( $remainingCounts-- == 0 ) {
92 rodolico 179
      &reportOutage( $name, $parameters );
90 rodolico 180
   }
181
   # open flag file, write new $remainingCounts to it
88 rodolico 182
}
89 rodolico 183
 
184
# we are up, so check for any flag file and unlink if found
185
sub cleanUp {
186
   my $name = shift;
94 rodolico 187
   print "$name => Success\n" if $config->{'TESTING'};
89 rodolico 188
   $name = &flagFileName( $name );
189
   unlink $name if -f $name;
190
}
191
 
192
#######################################################################
193
#                     Main Code
194
#######################################################################
195
 
196
# get the config file
197
$config = &loadConf( $configName );
198
 
199
# loop through each site to check
200
foreach my $testToRun( keys %{$config->{'sites to check'}} ) {
201
   # there is a faster way of doing this, but I don't remember it
202
   # you can merge two hashes, overwriting one with values if not existing in the other
203
   # I'll look it up, but for now
204
   foreach my $key ( keys %{$config->{'defaults'}} ) {
205
      $config->{'sites to check'}->{$testToRun}->{$key} = $config->{'defaults'}->{$key} unless defined $config->{'sites to check'}->{$testToRun}->{$key};
206
   }
207
   # run the test
208
   if ( &runTest( $config->{'sites to check'}->{$testToRun} ) ) {
209
      &cleanUp( $testToRun ); # success, clean up any old stuff
210
   } else { # failure, this is what we're here for
211
      &processFailure( $testToRun, $config->{'sites to check'}->{$testToRun} );
212
   }
213
}