# HG changeset patch # User devi # Date 1131355489 -7200 # Node ID 098664cf339c4cf7874688843d14af469fcdde81 # Parent 916661a893356fe3a1c4a4aa8c837eca4b85bd17 Выполнены шаги 4,5 в плане N05 по построению распределённой системы lilalo. Шаг <6> в настоящее время не является необходимым. Введено понятие сеанса. Сеансом считается процедура работы с системой, начинающаяся с регистрации в ней и зазаканчивающаяся разрегистрацией, и сопровождающаяся ведением одного файла скрипта. Одновременно с созданием скрипта (.script) создаётся соответствующий ему файл с информацией о сеансе (.info). Каждый сеанс имеет уникальный в пределах хоста идентификатор, ~local_session_id~, который впоследствии позволяет определить, какие команды относятся к какому сеансу. Добавлен backend-сервер, который получает данные от агентов и записывает из в backend (в настойщий момент - в XML-файл). Данные передаются по tcp-соединениям. (Одновременно может работать несколько серверов. Блокировка файла при записи пока что не выполняется ОСТОРОЖНО!!!!!!) Агент периодически пытается отправить backend-серверу содержимое своего кэш-файла, и если ему это удаётся, кэш файл очищается -- данные теперь хранятся в backend'е. Взаимодействие агентов, backend-сервера и frontend'а сейчас выполнеятся так: +-------+ | | | cache | | | +-^---+-+ | | . ^ v . ^^ . +---------+ . ^^ . / \ tcp / \ | | / \ CGI ( agent )----->( backend- )-->| backend |-->( frontend )-----> \ / \ сервер / | | \ / ' . ' ' .. ' +---------+ ' .. ' ^ | +----+----+ | | |*.script | | *.info | | | +---------+ l3-frontend: Теперь может выдавать результат работы на стандартный поток вывода. Вместо имени файла нужно указать символ - Добавлены файлы: l3-backend - backend-сервер l3-cgi - CGI-обвязка для l3-frontend'а Новые конфигурационные параметры: frontend_css Путь к файлу CSS, используемому в HTML-странице, которую генерирует frontend frontend_google_ico Путь к иконке google frontend_linux_ico Путь к иконке linux frontend_freebsd_ico Путь к иконке freebsd frontend_opennet_ico Путь к иконке opennet frontend_local_ico Путь к иконке локальной документации backend_address IP-адрес интерфейса, на котором работает backend-сервер backend_port Порт, который слушает backend-сервер backend_pidfile Путь к файлу, который хранит идентификатор процесса backend-сервера backend_datafile Путь к файлу хранилищу (файлу backend) diff -r 916661a89335 -r 098664cf339c l3-agent --- a/l3-agent Thu Nov 03 17:53:03 2005 +0200 +++ b/l3-agent Mon Nov 07 11:24:49 2005 +0200 @@ -10,6 +10,7 @@ use Text::Iconv; use Data::Dumper; use Time::Local 'timelocal_nocheck'; +use IO::Socket; use lib "."; use l3config; @@ -18,6 +19,7 @@ our @Command_Lines; our @Command_Lines_Index; our @Diffs; +our %Sessions; our %Commands_Stat; # Statistics about commands usage our %Files_Stat; # Statistics about commands usage @@ -44,7 +46,7 @@ sub save_cache_stat; sub load_cache_stat; - +sub print_session; sub load_diff_files { @@ -224,22 +226,50 @@ print "Loading lm-scripts...\n" if $Config{"verbose"} =~ /y/; - my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>; my $file; - my $files_number = $#lab_scripts; - my $ii = 0; my $skip_info; my $commandlines_loaded =0; my $commandlines_processed =0; + my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>; for $file (@lab_scripts){ - #printf "\t%i %3.2f\n", $ii, (100*$ii++/$files_number) if $Config{"verbose"} =~ /y/; # Пропускаем файл, если он не изменялся со времени нашего предудущего прохода my $size = (stat($file))[7]; next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size); + + my $local_session_id; + # Начальное значение идентификатора текущего сеанса определяем из имени скрипта + # Впоследствии оно может быть уточнено + $file =~ /.*\/(.*)\.script$/; + $local_session_id = $1; + + #Если файл только что появился, + #пытаемся найти и загрузить информацию о соответствующей ему сессии + if (!$Script_Files{$file}) { + my $session_file = $file; + $session_file =~ s/\.script/.info/; + if (open(SESSION, $session_file)) { + local $/; + my $data = ; + close(SESSION); + + for my $session_data ($data =~ m@(.*?)@sg) { + my %session; + while ($session_data =~ m@<([^>]*?)>(.*?)@sg) { + $session{$1} = $2; + } + $local_session_id = $session{"local_session_id"} if $session{"local_session_id"}; + $Sessions{$session_id}=\%session; + } + + #Загруженную информацию сразу же отправляем в поток + print_session($Config{cache}, $local_session_id); + } + } + open (FILE, "$file"); binmode FILE; @@ -278,7 +308,8 @@ =cut -ТАБЛИЦА КОМАНД +Атрибуты cline +Список полей, характеризующих командную строку uid Идентификатор пользователя @@ -338,6 +369,7 @@ Текстовый комментарий к команде. Может генерироваться из самого лога с помощью команд #^ Комментарий + #= Комментарий #v Комментарий в том случае, если для комментирования достаточно одной строки, или с помощью команд @@ -348,9 +380,11 @@ В последнем случае комментарий может содержать заголовок, абзацы и несложное форматирование. - Символ ^ или v после знака комментария # обозначает, + Символы ^, v или = после знака комментария # обозначает, к какой команде относится комментарий: - к предыдущей (^) или последующей (v) + к предыдущей (^), последующей (v) + или это общий комментарий по тексту, не относящийся непосредственно + ни к одной из них (=) err Код завершения командной строки @@ -397,22 +431,22 @@ 1 - версия использующаяся в lilalo - raw_file (*) + raw_file Имя файла, в котором находится бинарное представление журнала. Может содержать ключевое слово HERE, обозначающее что бинарное представление хранится непосредственно в базе данных в атрибуте raw_data - raw_start (*) + raw_start Начало блока командной строки в файле бинарного представления - raw_output_start (*) + raw_output_start Начало блока вывода - raw_end (*) + raw_end Конец блока командной строки в файле бинарного представления - raw_cline (*) + raw_cline Необработанная командная строка (без приглашения) в бинарном виде raw_data (*) @@ -425,11 +459,12 @@ Информация о сеансах - + (см. lm-install) =cut + $cl{"local_session_id"} = $local_session_id; # Parse new command $cl{"uid"} = $3; $cl{"euid"} = $cl{"uid"}; # Если в команде обнаружится sudo, euid поменяем на 0 @@ -751,6 +786,7 @@ # Начинаем вывод команды print OUT "\n"; + print OUT "",$cl->{session_id},"\n"; print OUT "\n"; print OUT "",$cl->{raw_start},"\n"; print OUT "",$cl->{raw_output_start},"\n"; @@ -789,7 +825,54 @@ #print OUT "\n"; close(OUT); - save_cache_stat(); +} + +sub print_session +{ + my $output_filename = $_[0]; + my $local_session_id = $_[1]; + return if not defined($Sessions{$local_session_id}); + + open(OUT, ">>", $output_filename) + or die "Can't open $output_filename for writing\n"; + print OUT "\n"; + my %session = %{$Sessions{$local_session_id}}; + for my $key (keys %session) { + print OUT "<$key>".$session{$key}."\n" + } + print OUT "\n"; + close(OUT); +} + +sub send_cache +{ + `logger "step 0"`; + `logger "step 1"`; + + # Если в кэше что-то накопилось, + # попытаемся отправить это на сервер + # + my $cache_was_sent=0; + + if (open(CACHE, $Config{cache})) { + local $/; + my $cache = ; + close(CACHE); + + my $socket = IO::Socket::INET->new( + PeerAddr => $Config{backend_address}, + PeerPort => $Config{backend_port}, + proto => "tcp", + Type => SOCK_STREAM + ); + + if ($socket) { + print $socket $cache; + close($socket); + $cache_was_sent = 1; + } + } + return $cache_was_sent; } sub save_cache_stat @@ -805,6 +888,7 @@ { if (open (CACHE, "$Config{cache_stat}")) { while() { + chomp; my ($f, $size, $tell) = split /\t/; $Script_Files{$f}->{size} = $size; $Script_Files{$f}->{tell} = $tell; @@ -813,65 +897,6 @@ }; } -=cut -sub print_command_lines2 -{ - my $output_filename=$_[0]; - open(OUT, ">", $output_filename) - or die "Can't open $output_filename for writing\n"; - - - print OUT < -OUT - - my $cl; - for my $i (@Command_Lines_Index) { - - - $cl = $Command_Lines[$i]; - - -# Printing out - print OUT < - $cl->{day} - $cl->{hour} - $cl->{min} - $cl->{sec} - $cl->{tty} - $cl->{uid} - $cl->{euid} - $cl->{prompt} - $cl->{cline} - $cl->{err} - -$cl->{output} - -OUT - } - - for my $diff (@Diffs) { - - print OUT < - $diff->{path} - $diff->{uid} - $diff->{day} - $diff->{hour} - $diff->{min} - $diff->{sec} - -$diff->{text} - -OUT - } - - print OUT < -OUT -} -=cut main(); @@ -882,73 +907,85 @@ sub main { -$| = 1; -init_variables(); -init_config(); + $| = 1; -for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) { - load_diff_files($lab_log); -} + init_variables(); + init_config(); -if ($Config{"mode"} ne "daemon") { - load_command_lines($Config{"input"}, $Config{"input_mask"}); - sort_command_lines; - process_command_lines; - print_command_lines($Config{"cache"}); -} -else { - if (open(PIDFILE, $Config{agent_pidfile})) { - my $pid = ; - close(PIDFILE); - if ( ! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`) { - print "Removing stale pidfile\n"; - unlink $Config{agent_pidfile}; - or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!"; + for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) { + load_diff_files($lab_log); + } + + if ($Config{"mode"} ne "daemon") { + +=cut + В нормальном режиме работы нужно + считать скрипты, обработать их и записать + результат выполнения в результриующий файл. + После этого завершить работу. +=cut + load_command_lines($Config{"input"}, $Config{"input_mask"}); + sort_command_lines; + process_command_lines; + print_command_lines($Config{"cache"}); + } + else { + if (open(PIDFILE, $Config{agent_pidfile})) { + my $pid = ; + close(PIDFILE); + if ( ! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`) { + print "Removing stale pidfile\n"; + unlink $Config{agent_pidfile} + or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!"; + } + else { + print "l3-agent is already running\n"; + exit(0); + } } - else { - print "l3-agent is already running\n"; - exit(0); + if ($Config{detach} =~ /^y/i) { + #$Config{verbose} = "no"; + my $pid = fork; + exit if $pid; + die "Couldn't fork: $!" unless defined ($pid); + + open(PIDFILE, ">", $Config{agent_pidfile}) + or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!"; + print PIDFILE $$; + close(PIDFILE); + + for my $handle (*STDIN, *STDOUT, *STDERR) { + open ($handle, "+<", "/dev/null") + or die "can't reopen $handle to /dev/null: $!" + } + + POSIX::setsid() + or die "Can't start a new session: $!"; + + $0 = $Config{"l3-agent"}; + + $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed; } + while (not $Killed) { + @Command_Lines = (); + @Command_Lines_Index = (); + load_cache_stat(); + load_command_lines($Config{"input"}, $Config{"input_mask"}); + if (@Command_Lines) { + sort_command_lines; + process_command_lines; + print_command_lines($Config{"cache"}); + } + save_cache_stat(); + if (-e $Config{cache} && (stat($Config{cache}))[7]) { + send_cache() && unlink($Config{cache}); + } + sleep($Config{"daemon_sleep_interval"} || 1); + } + + unlink $Config{agent_pidfile}; } - if ($Config{detach} =~ /^y/i) { - #$Config{verbose} = "no"; - my $pid = fork; - exit if $pid; - die "Couldn't fork: $!" unless defined ($pid); - - open(PIDFILE, ">", $Config{agent_pidfile}) - or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!"; - print PIDFILE $$; - close(PIDFILE); - - for my $handle (*STDIN, *STDOUT, *STDERR) { - open ($handle, "+<", "/dev/null") - or die "can't reopen $handle to /dev/null: $!" - } - - POSIX::setsid() - or die "Can't start a new session: $!"; - - $0 = $Config{"l3-agent"}; - - $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed; - } - while (not $Killed) { - @Command_Lines = (); - @Command_Lines_Index = (); - load_cache_stat(); - load_command_lines($Config{"input"}, $Config{"input_mask"}); - if (@Command_Lines) { - sort_command_lines; - process_command_lines; - print_command_lines($Config{"cache"}); - } - sleep($Config{"daemon_sleep_interval"} || 1); - } - - unlink $Config{agent_pidfile}; -} } diff -r 916661a89335 -r 098664cf339c l3-backend --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/l3-backend Mon Nov 07 11:24:49 2005 +0200 @@ -0,0 +1,106 @@ +#!/usr/bin/perl + +use strict; +use lib '.'; +use l3config; +use IO::Socket; +use POSIX qw(:sys_wait_h); + +sub main; + +main(); + +sub REAPER { + 1 until (-1 == waitpid(-1, WNOHANG)); + $SIG{CHLD} = \&REAPER; +} + +sub process_was_killed +{ + # Здесь должна быть красивая процедура + # завершения демона + unlink $Config{backend_pidfile}; + exit(0); +} + +sub main { + init_config(); + + + # Проверяем, возможно демон уже запущен + # Если он работает, просто завершаемся + if (open(PIDFILE, $Config{backend_pidfile})) { + my $pid = ; + close(PIDFILE); + if ( ! -e "/proc/$pid" || !`grep $Config{"l3-backend"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`) { + print "Removing stale pidfile\n"; + unlink $Config{backend_pidfile} + or die "Can't remove stale pidfile ". $Config{backend_pidfile}. " : $!"; + } + else { + print "l3-backend is already running\n"; + exit(0); + } + } + + # Уходим в background, если необходимо + if ($Config{detach} =~ /^y/i) { + #$Config{verbose} = "no"; + my $pid = fork; + exit if $pid; + die "Couldn't fork: $!" unless defined ($pid); + + open(PIDFILE, ">", $Config{backend_pidfile}) + or die "Can't open pidfile ". $Config{backend_pidfile}. " for wrting: $!"; + print PIDFILE $$; + close(PIDFILE); + + for my $handle (*STDIN, *STDOUT, *STDERR) { + open ($handle, "+<", "/dev/null") + or die "can't reopen $handle to /dev/null: $!" + } + + POSIX::setsid() + or die "Can't start a new session: $!"; + + $0 = $Config{"l3-backend"}; + + $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed; + } + + # Открываем сетевой сокет и слушаем + my $server = IO::Socket::INET->new( + LocalPort => $Config{backend_port}, + Type => SOCK_STREAM, + Reuse => 1, + Listen => 10 ); + + if (!$server) { + die "Couldn't bind to socket ".$Config{backend_port}."\n"; + } + + $SIG{CHLD} = 'IGNORE'; + + # При получении новых соединенений, + # порождаем дочерние процессы + while (my $client = $server->accept()) { + my $pid; + next if $pid = fork; + die "fork: $!" unless defined $pid; + + # Это наш ответвлённый клиент + close($server); + + # Считываем данные и передаём их в точку получения + open(OUT, ">>", $Config{"backend_datafile"}); + select OUT; $|=1; + while(<$client>) { + print OUT $_; + } + close(OUT); + } + continue { + # Наш родитель + close ($client); + } +} diff -r 916661a89335 -r 098664cf339c l3-cgi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/l3-cgi Mon Nov 07 11:24:49 2005 +0200 @@ -0,0 +1,17 @@ +#!/usr/bin/perl + +use strict; +use CGI qw(:standard); + +my $value = param('PARAM'); + +print header( + -charset => "utf-8", + ); +chdir("/home/devi/cvs/lilalo"); +open (FRONTEND, "./l3-frontend --output - |"); +while () { + print; +} +close(FRONTEND); + diff -r 916661a89335 -r 098664cf339c l3-frontend --- a/l3-frontend Thu Nov 03 17:53:03 2005 +0200 +++ b/l3-frontend Mon Nov 07 11:24:49 2005 +0200 @@ -29,7 +29,7 @@ init_variables(); init_config(); - load_command_lines_from_xml($Config{"cache"}); + load_command_lines_from_xml($Config{"backend_datafile"}); print_command_lines($Config{"output"}); } @@ -334,7 +334,7 @@ - +