Automating UNIX and Linux Administration
by Kirk Bauer
Chapter 10 : System Monitoring
Скрипты для этой книги лежат тут (40 кб)
Для администратора мониторинг компьютеров в сети должен быть построен так ,
чтобы он мог получать отчет о неисправностях не только после их возникновения ,
но и мог бы предотвращать их появление.
Мониторинг можно разделить на 3 основных части :
1. Проверка системы на уровне железа - доступное дисковое пространство ,
неполадки в работе драйверов и т.д.
2. Проверка логов на предмет аномалий.
3. Проверка сервисов .
Система отчетов
Следующий перловый скрипт имеет 2 командных аргумента .
Первый - уровень значимости (WARNING или CRITICAL),
второй собственно само сообщение ("disk failure").
Аргумент под названием stdin может включать многострочный
отчет . Начало скрипта будет таким :
#!/usr/bin/perl -w
use strict;
# Configuration items
my $MailThreshold = 'WARNING';
my $LogFile = '/var/log/event.log';
my $Email = 'alert@company.com';
# Available log levels
my %Levels = (
'INFO' => 1,
'WARNING' => 2,
'ERROR' => 3,
'CRITICAL' => 4
);
sub usage () {
print STDERR "Usage: $0 [--stdin] \n";
print STDERR "Levels: ";
foreach (keys %Levels) {
print STDERR "$_ ";
}
print STDERR "\n";
exit 1;
}
Письмо будет отправлено по адресу $Email , при этом отчет ляжет в $LogFile.
Следующая часть скрипта проверяет аргументы,проверяет имя хоста:
# Check and store parameters
my $stdin = 0;
if ($ARGV[0] eq '--stdin') {
shift @ARGV;
$stdin = 1;
}
usage() unless ($#ARGV == 1);
usage() if ($ARGV[0] eq '--help');
my ($level, $subject) = @ARGV;
$level = uc($level);
usage() unless ($Levels{$level});
# Determine system's hostname (first portion only)
my $hostname = 'hostname';
chomp($hostname);
$hostname =~ s/\..*$//;
# Store formatted date string
my $date = localtime;
Следующая часть скрипта сработает при условии , что внешний аргумент
–stdin пустой :
open (LOG, ">>$LogFile");
unless ($stdin) {
if ($Levels{$level} >= $Levels{$MailThreshold}) {
system ("mail -s '[$level] $hostname: $subject' '$Email'");
}
print LOG "$date $hostname [$level] $subject";
close(LOG);
exit 0;
}
Следующая часть скрипта сработает при условии ,
что внешний аргумент –stdin непустой :
Каждая строка stdin будет добавлена к логу .
При этом они сохраняются в массиве.
my @lines;
while (my $line = ) {
push @lines, $line;
print LOG "$date $hostname [$level] $subject: $line";
}
close(LOG);
if ((@lines) and $Levels{$level} >= $Levels{$MailThreshold}) {
open (MAIL, "| mail -s '[$level] $hostname: $subject' '$Email'");
foreach (@lines) {
print MAIL $_;
}
close(MAIL);
}
exit 0;
Использовать этот скрипт можно по-разному . например ,
usr/local/sbin/report INFO 'Test report' < /dev/null
В следующем примере в лог уйдет доступное дисковое пространство :
df | /usr/local/sbin/report --stdin INFO 'Available drive space'
Если мы хотим допустим проверить загрузку системы , мы набираем команду :
uptime
10:18am up 1:16, 1 user, load average: 0.29, 0.20, 0.18
Если мы хотим , чтобы при критических значениях сообщение
о перегрузке поступало в лог , можно с помощью крона запускать
с определенной периодичностью такую команду :
uptime | awk '{if ($10 > 1.00) print "15-min average: " $10}' | \
/usr/local/sbin/report --stdin WARNING 'High Load Average'
Следующий шелловский скрипт проверяет доступное дисковое пространство
для файловых систем , определенных
в переменной $types :
#!/bin/bash
types="ext2|ext3|ufs|vfat"
cutoff="90"
for drive in 'mount | awk "/type ($types)/ {print \\\$1}"' ; do
df "$drive" | awk -v "cutoff=$cutoff" '/^\// {
gsub(/%$/, "", $5);
if ($5 > cutoff)
print "Drive " $1 " (" $6 ") is " $5 "% Full"
}'
done | /usr/local/sbin/report --stdin WARNING 'Drives almost full'
Рассмотрим подробнее работу этого скрипта . Во-первых, командой mount
мы определяем доступные партиции .
Затем для каждой партиции запускается команда df .
С помощью команды awk мы обрабатываем вывод
Мы передаем для awk аргумент cutoff .
awk будет обрабатывать только те строки , которые начинаются со слэша .
Функция gsub используется для удаления символа процента
в 5-м столбце для того , чтобы извлечь число ,
которое сравнивается с cutoff .
Если число болше , чем cutoff , для данной партиции генерится output .
Кроном такой скрипт может запускаться раз в день .
В каждой системе есть сервисы-демоны , которые работают постоянно .
Для удаленного доступа это сервис sshd .
Также это могут быть mail, DNS, web server.
Проверка сервиса sshd :
ps ax -o '%c %P' | grep 'sshd'
sshd 1
sshd 12599
sshd 12599
sshd 12599
sshd 12599
sshd 12599
sshd 12599
sshd_checker 1
Мы видим , что во 2-м столбце выводятся id-шники как родительского ,
так и дочерних процессов .
нам интересен только родительский :
ps ax -o '%c %P' | grep 'sshd' | grep '1$'
sshd 1
sshd_checker 1
отфильтруем до нужной кондиции
% ps ax -o '%c %P' | awk '{if (($2 == 1) && ($1 == "sshd")) print $0}'
sshd 1
Для проверки удаленного демона можно запустить скрипт на веб-сервере .
Следующий скрипт проверяет URL каждые 30 секунд ,
при этом для HTTP-запроса используется wget :
#!/bin/bash
SLEEP=30 #seconds
TIMEOUT=10 #seconds
URL='http://localhost/index.html'
MATCH=''
while true ; do
wget -q -O - -T=$TIMEOUT --tries=1 "$URL" | grep -q "$MATCH" || {
/usr/local/sbin/report ERROR "Web server not responding"
/etc/rc.d/init.d/httpd restart && {
/usr/local/sbin/report INFO "Web server restarted"
}
}
sleep $SLEEP
done
Следующий скрипт запускает команду rpm -qa ,
которая проверяет список установленных пакетов ,
сравнивает с предыдущим списком .
Команда sed обрабатывает output .
!/bin/bash
TMPDIR="$HOME/tmp"
rpm -qa | sort > $TMPDIR/packages.curr
if [ -r $TMPDIR/packages.last ] ; then
diff $TMPDIR/packages.last $TMPDIR/packages.curr | \
sed -n -e 's/^/Added/p' | \
/usr/local/sbin/report --stdin INFO 'Packages changed'
fi
mv $TMPDIR/packages.curr $TMPDIR/packages.last
Monitoring Network Services
Простейшая форма проверки сети - пинг .
Но пинг ничего нам не скажет о состоянии удаленной системы ,
если даже она отвечает .
Следующая форма мониторинга - проверка портов .
Коннект на 80-й порт говорит о том , что по крайней
мере на машине работает веб-сервер .
Рассмотрим пример скрипта , который проверяет демона .
Запустим команду , которая проверяет список запущенных процессов :
ps ax
PID TTY STAT TIME COMMAND
1 ? S 1:46 init
20288 ? S 0:06 /usr/sbin/httpd -DHAVE_PROXY...
Обработаем вывод этой команды в скрипте :
#!/bin/bash
process="/usr/sbin/httpd"
start="service httpd restart"
ps ax | awk '{print $5}' | grep -q "^$process$" || {
# Apparently not running, so start the process
eval "$start"
exit $?
}
exit 0
Скрипт имеет 2 переменных - имя проверяемого демона (httpd) и команда ,
которая запускается в случае ,
если проверяемый демон не запущен .
Следующий скрипт проверяет порт .
Для начала запустим команду :
netstat -ln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN
...
Преобразуем вывод :
netstat -ln | awk '/^tcp/ {print $4}'
0.0.0.0:80
0.0.0.0:6000
0.0.0.0:22
Теперь скрипт :
#!/bin/bash
port="80"
restart="service httpd restart"
netstat -ln | awk '/^tcp/ {print $4}' | grep -q ":$port$" || {
# Apparently not listening, so run restart command
eval "$restart"
exit $?
}
exit 0
В следующем скрипте делается запрос на удаленный URL и проверяется
веб-сервис :
#!/bin/bash
URL="http://localhost/netsaint/index.html"
TIMEOUT=10 #(seconds)
MATCH=""
restart="service httpd restart"
wget -q -O - -T=$TIMEOUT --tries=1 "$URL" | grep -q "$MATCH" || {
# Something is wrong, so restart
eval "$restart"
exit $?
}
exit 0
|