lilalo
annotate lm @ 25:ba4d6515b8fd
Выполнен шаг (3) в плане (N05) по построению распределённой системы lilalo.
Агент l3-агент в реальном времени анализирует скрипты в указанном ему
каталоге и по мере обнаружения новых завершённых команд записывает их
в кэш-файл.
Данные о том, докуда разобран каждый скрипт-файл сохраняются во временном
файле, для того чтобы при перезапуске агента он мог продолжить разбор
с того места, где он был остановлен в прошлый раз, а не копировал
данные в кэш-файл повторно.
Агент запускается для каждого пользователя системы.
Если агент обнаружил свою копию работающую от имени того же пользователя,
он автоматически завершается.
Поиск копии агента выполняется так:
просматривается pid-файл агента - если его нет, считается, что и агент не запущен
(Внимание! Не удаляйте pid-файл!! Работа нескольких агентов от имени одного
пользователя может быть некорректной!)
Если он есть, выполняется проверка, действительно ли процесс с таким идентификатором
это l3-агент текущего пользователя. Если нет, pid-файл удаляется, и агент запускается.
Нормальное завершение агента, работающего в режиме демона, выполняется
с помощью сигнала TERM. При завершении агент автоматически стирает свой pid-файл.
Добавлены атрибуты команды, хранящие информацию о участке бинарного файла скрипта,
соответствующей команды:
raw_start - начало блока команды
raw_output_start - начало вывода команды
raw_end - окончание вывода
raw_file - имя бинарного файла
Файлы:
(могут меняться с помощью конфигурационных параметров)
~/.labmaker/.cache.dat
~/.labmaker/cache.xml
~/.labmaker/l3-agent.pid
Конфигурационные параметры:
cache_stat Имя файла с информацией о текущей позиции разбора
в каждом файле
mode Режим, в котором работает агент.
Допустимые значения:
daemon - в режиме непрерывного опроса каталога
Программа не завершается после окончания анализа,
а ждёт появления новых данных
normal - однократный анализ каталога.
Программа завершается после окончания анализа данных
daemon_sleep_interval Интервал через который агент просматривает каталог скриптов
в поисках новых данных
detach Нужно ли выполнять отключение от терминала при работе в режиме демона?
(строго говоря, если процесс не отключился от терминала,
то и в режиме демона он работать не может. Здесь имеется в виду
режим непрерывного опроса каталога)
agent_pidfile Путь к файлу, который будет хранить идентификатор процесса агента.
l3-agent Имя, под которым будет известен процесс l3-agent
Незначительные исправления:
* убрана отладочная информация о new_commands и new_files из frontend'а
Агент l3-агент в реальном времени анализирует скрипты в указанном ему
каталоге и по мере обнаружения новых завершённых команд записывает их
в кэш-файл.
Данные о том, докуда разобран каждый скрипт-файл сохраняются во временном
файле, для того чтобы при перезапуске агента он мог продолжить разбор
с того места, где он был остановлен в прошлый раз, а не копировал
данные в кэш-файл повторно.
Агент запускается для каждого пользователя системы.
Если агент обнаружил свою копию работающую от имени того же пользователя,
он автоматически завершается.
Поиск копии агента выполняется так:
просматривается pid-файл агента - если его нет, считается, что и агент не запущен
(Внимание! Не удаляйте pid-файл!! Работа нескольких агентов от имени одного
пользователя может быть некорректной!)
Если он есть, выполняется проверка, действительно ли процесс с таким идентификатором
это l3-агент текущего пользователя. Если нет, pid-файл удаляется, и агент запускается.
Нормальное завершение агента, работающего в режиме демона, выполняется
с помощью сигнала TERM. При завершении агент автоматически стирает свой pid-файл.
Добавлены атрибуты команды, хранящие информацию о участке бинарного файла скрипта,
соответствующей команды:
raw_start - начало блока команды
raw_output_start - начало вывода команды
raw_end - окончание вывода
raw_file - имя бинарного файла
Файлы:
(могут меняться с помощью конфигурационных параметров)
~/.labmaker/.cache.dat
~/.labmaker/cache.xml
~/.labmaker/l3-agent.pid
Конфигурационные параметры:
cache_stat Имя файла с информацией о текущей позиции разбора
в каждом файле
mode Режим, в котором работает агент.
Допустимые значения:
daemon - в режиме непрерывного опроса каталога
Программа не завершается после окончания анализа,
а ждёт появления новых данных
normal - однократный анализ каталога.
Программа завершается после окончания анализа данных
daemon_sleep_interval Интервал через который агент просматривает каталог скриптов
в поисках новых данных
detach Нужно ли выполнять отключение от терминала при работе в режиме демона?
(строго говоря, если процесс не отключился от терминала,
то и в режиме демона он работать не может. Здесь имеется в виду
режим непрерывного опроса каталога)
agent_pidfile Путь к файлу, который будет хранить идентификатор процесса агента.
l3-agent Имя, под которым будет известен процесс l3-agent
Незначительные исправления:
* убрана отладочная информация о new_commands и new_files из frontend'а
author | devi |
---|---|
date | Thu Nov 03 17:49:56 2005 +0200 (2005-11-03) |
parents | 05d496f33d76 |
children | 4d252e7dd478 |
rev | line source |
---|---|
devi@0 | 1 #!/usr/bin/perl |
devi@0 | 2 |
devi@0 | 3 |
devi@0 | 4 use strict; |
devi@0 | 5 use Inline::Files; |
devi@0 | 6 use Data::Dumper; |
devi@0 | 7 use Switch; |
devi@0 | 8 use XML::Simple; |
devi@0 | 9 use Getopt::Long; |
devi@4 | 10 use utf8; |
devi@0 | 11 |
devi@0 | 12 our $XMLClass; |
devi@0 | 13 our $XMLCourse; |
devi@0 | 14 our @Labs; |
devi@0 | 15 |
devi@0 | 16 our %Machines; # Machines list from class.xml |
devi@0 | 17 our @SelectedMachines; # Machines list given as the command line argument |
devi@0 | 18 |
devi@0 | 19 our $Config_File = "labmaker.conf"; |
devi@0 | 20 our %Config = ( |
devi@0 | 21 "show_host" => "no", |
devi@0 | 22 |
devi@3 | 23 # Вспомогательные программы |
devi@23 | 24 #"l3-report" => "./lm-report", |
devi@23 | 25 "l3-report" => "./l3-report", |
devi@3 | 26 |
devi@0 | 27 # Каталоги |
devi@13 | 28 "path_lilalo" => "/var/lilalo/", |
devi@10 | 29 "path_classes" => "/var/lilalo/classes/", |
devi@10 | 30 "path_lablogs" => "/var/lilalo/lablogs/", |
devi@10 | 31 "courses_path" => "/var/lilalo/courses/", |
devi@10 | 32 "outpath" => "/var/lilalo/out/", |
devi@3 | 33 "path_web" => "/var/www/l3", # Путь к web-отчётам |
devi@3 | 34 "path_share" => "./share/", # Путь к web-отчётам |
devi@0 | 35 |
devi@0 | 36 # Файлы |
devi@0 | 37 "runfile" => "lm.run", |
devi@0 | 38 "logfile" => "lm.log", |
devi@0 | 39 |
devi@0 | 40 "class" => "class", # Имя файла класса |
devi@0 | 41 "class_suffix" => ".xml", # Cуффикс файла класса |
devi@5 | 42 "classfile" => "", |
devi@0 | 43 |
devi@0 | 44 "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub", |
devi@0 | 45 "lmssh" => "./lm-ssh", |
devi@0 | 46 "lminstall" => "./lm-install", |
devi@17 | 47 "ssh_user" => "root", |
devi@0 | 48 ); |
devi@0 | 49 |
devi@0 | 50 our %Run = ( |
devi@0 | 51 "lab" => "" |
devi@0 | 52 ); |
devi@0 | 53 |
devi@0 | 54 our %Scripts; |
devi@0 | 55 |
devi@0 | 56 sub load_class; |
devi@0 | 57 sub load_config; |
devi@0 | 58 sub load_course; |
devi@0 | 59 sub load_scripts; |
devi@0 | 60 |
devi@0 | 61 sub lm_next; |
devi@0 | 62 sub lm_prev; |
devi@0 | 63 sub lm_start; |
devi@0 | 64 sub lm_stop; |
devi@0 | 65 sub lm_set; |
devi@0 | 66 sub lm_do; |
devi@0 | 67 sub lm_report; |
devi@0 | 68 sub lm_show_hosts; |
devi@0 | 69 sub lm_show_labs; |
devi@0 | 70 |
devi@0 | 71 sub load_run; |
devi@0 | 72 sub save_run; |
devi@0 | 73 sub print_log; |
devi@0 | 74 sub print_usage_info; |
devi@0 | 75 sub main(); |
devi@0 | 76 |
devi@0 | 77 main(); |
devi@0 | 78 |
devi@0 | 79 sub main() |
devi@0 | 80 { |
devi@0 | 81 binmode STDOUT, ":utf8"; |
devi@0 | 82 |
devi@0 | 83 if (! @ARGV) { |
devi@0 | 84 print_usage_info(); |
devi@0 | 85 exit(0); |
devi@0 | 86 } |
devi@0 | 87 |
devi@0 | 88 load_config; |
devi@0 | 89 load_run; |
devi@0 | 90 load_scripts; |
devi@0 | 91 load_class; |
devi@0 | 92 load_course; |
devi@0 | 93 |
devi@0 | 94 my $arg = join " ", @ARGV; |
devi@0 | 95 |
devi@0 | 96 # Getting @SelectedMachines if any |
devi@0 | 97 if ($arg =~ s/@(.*?)\s//) { |
devi@0 | 98 my $machines = $1; |
devi@0 | 99 my @list = split /,/, $machines; |
devi@0 | 100 for my $interval (@list) { |
devi@0 | 101 my ($first, $last) = split /-/, $interval; |
devi@0 | 102 |
devi@0 | 103 push @SelectedMachines, $first; |
devi@0 | 104 while ($first < $last) { |
devi@0 | 105 push @SelectedMachines, ++$first; |
devi@0 | 106 } |
devi@0 | 107 } |
devi@0 | 108 } |
devi@0 | 109 |
devi@0 | 110 # Choose command to do |
devi@0 | 111 switch ($arg) { |
devi@0 | 112 case "next" { lm_next } |
devi@0 | 113 case "prev" { lm_prev } |
devi@0 | 114 case /set / { $arg =~ /set (.*)/; lm_set $1 } |
devi@0 | 115 case "report" { lm_report } |
devi@0 | 116 case "start" { lm_start } |
devi@0 | 117 case "stop" { lm_stop } |
devi@0 | 118 case "show hosts" { lm_show_hosts } |
devi@0 | 119 case "show labs" { lm_show_labs } |
devi@0 | 120 case /do / { $arg =~ /do (.*)/; lm_do "$1" } |
devi@0 | 121 else { print_usage_info() } |
devi@0 | 122 } |
devi@0 | 123 save_run; |
devi@0 | 124 exit(0); |
devi@0 | 125 } |
devi@0 | 126 |
devi@0 | 127 sub load_scripts |
devi@0 | 128 { |
devi@0 | 129 local $/; |
devi@0 | 130 $_=<SCRIPTS>; |
devi@0 | 131 %Scripts = ("empty-element", split (/###(.*)\n/)); |
devi@0 | 132 delete($Scripts{"empty-element"}); |
devi@0 | 133 } |
devi@0 | 134 |
devi@0 | 135 sub load_config |
devi@0 | 136 { |
devi@0 | 137 my %file_config; |
devi@0 | 138 my %argv_config; |
devi@0 | 139 #read_config_file(\%file_config, $Config_File); |
devi@0 | 140 GetOptions(\%argv_config, map "$_=s", keys %Config); |
devi@0 | 141 %Config = (%Config, %file_config, %argv_config); |
devi@0 | 142 } |
devi@0 | 143 |
devi@0 | 144 sub load_course |
devi@0 | 145 { |
devi@0 | 146 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 ) |
devi@0 | 147 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n"; |
devi@0 | 148 # print Dumper($XMLCourse); |
devi@0 | 149 for my $lab (@{$XMLCourse->{"module"}}) { |
devi@0 | 150 push @Labs, $lab->{"code"}; |
devi@0 | 151 } |
devi@0 | 152 } |
devi@0 | 153 |
devi@0 | 154 sub load_class |
devi@0 | 155 { |
devi@0 | 156 my $classfile = |
devi@5 | 157 $Config{"classfile"} || |
devi@0 | 158 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"}; |
devi@0 | 159 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] ) |
devi@0 | 160 or die "Can't open file of the class ",$classfile,"\n"; |
devi@0 | 161 |
devi@0 | 162 for my $student (@{$XMLClass->{"student"}}) { |
devi@0 | 163 $Machines{$student->{"host"}} = { |
devi@0 | 164 "name" => "$student->{firstname} $student->{surname}", |
devi@0 | 165 "user" => "$student->{user}", |
devi@0 | 166 "student" => $student, |
devi@0 | 167 } |
devi@0 | 168 } |
devi@0 | 169 # print Dumper($XMLClass); |
devi@0 | 170 # print Dumper(\%Machines); |
devi@0 | 171 } |
devi@0 | 172 |
devi@0 | 173 |
devi@0 | 174 sub lm_next |
devi@0 | 175 { |
devi@0 | 176 for(my $i=0; $i<=$#Labs; $i++){ |
devi@0 | 177 if ( $Labs[$i] eq $Run{"lab"} ) { |
devi@0 | 178 if ($i < $#Labs) { |
devi@0 | 179 lm_set($Labs[$i+1]); |
devi@0 | 180 return ; |
devi@0 | 181 } else { |
devi@0 | 182 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible" |
devi@0 | 183 } |
devi@0 | 184 } |
devi@0 | 185 |
devi@0 | 186 } |
devi@0 | 187 die "Lab ", $Run{"lab"}, " not found. Don't know which is next" |
devi@0 | 188 } |
devi@0 | 189 |
devi@0 | 190 sub lm_prev |
devi@0 | 191 # Switch to previous lab |
devi@0 | 192 { |
devi@0 | 193 for(my $i=0; $i<=$#Labs; $i++){ |
devi@0 | 194 if ( $Labs[$i] eq $Run{"lab"} ) { |
devi@0 | 195 if ($i > 0) { |
devi@0 | 196 lm_set($Labs[$i-1]); |
devi@0 | 197 return ; |
devi@0 | 198 } else { |
devi@0 | 199 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible" |
devi@0 | 200 } |
devi@0 | 201 } |
devi@0 | 202 |
devi@0 | 203 } |
devi@0 | 204 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous" |
devi@0 | 205 } |
devi@0 | 206 |
devi@0 | 207 sub lm_set |
devi@0 | 208 # Switch to $_[0] lab |
devi@0 | 209 # FIXME |
devi@0 | 210 { |
devi@0 | 211 my $lab = shift; |
devi@0 | 212 print "Current lab is $lab\n"; |
devi@0 | 213 $Run{"lab"} = "$lab"; |
devi@0 | 214 lm_do "setlab", $lab; |
devi@0 | 215 } |
devi@0 | 216 |
devi@0 | 217 |
devi@0 | 218 sub lm_start |
devi@0 | 219 # Start new training day |
devi@0 | 220 { |
devi@0 | 221 print_log(`date`." STARTED\n"); |
devi@0 | 222 if ($Run{"lab"}) { |
devi@0 | 223 lm_next; |
devi@0 | 224 } |
devi@0 | 225 else |
devi@0 | 226 { |
devi@0 | 227 # First lab in the course |
devi@0 | 228 lm_set($Labs[0]); |
devi@0 | 229 } |
devi@0 | 230 } |
devi@0 | 231 |
devi@0 | 232 sub lm_stop |
devi@0 | 233 # Stop this training day |
devi@0 | 234 { |
devi@0 | 235 print_log(`date`." STOPPED\n"); |
devi@0 | 236 } |
devi@0 | 237 |
devi@0 | 238 |
devi@0 | 239 sub lm_show_hosts |
devi@0 | 240 # Show hosts used to run a commands |
devi@0 | 241 { |
devi@0 | 242 my $i=1; |
devi@0 | 243 for my $m (sort keys %Machines) { |
devi@0 | 244 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) { |
devi@0 | 245 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n"; |
devi@0 | 246 } |
devi@0 | 247 $i++; |
devi@0 | 248 } |
devi@0 | 249 } |
devi@0 | 250 |
devi@0 | 251 sub lm_show_labs |
devi@0 | 252 # Show hosts used to run a commands |
devi@0 | 253 { |
devi@0 | 254 my $i=1; |
devi@0 | 255 for my $lab (@Labs) { |
devi@0 | 256 print $lab; |
devi@0 | 257 print "*" if $lab eq $Run{"lab"}; |
devi@0 | 258 print "\n"; |
devi@0 | 259 } |
devi@0 | 260 } |
devi@0 | 261 |
devi@0 | 262 sub lm_do |
devi@0 | 263 # Do the $_[0] command on all of the hosts |
devi@0 | 264 { |
devi@0 | 265 my $command = shift; |
devi@0 | 266 my $arg = join " ", @_; |
devi@0 | 267 my $i=1; |
devi@0 | 268 for my $m (sort keys %Machines) { |
devi@0 | 269 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) { |
devi@0 | 270 print "$m:\n" if $Config{"show_host"} =~ /y/i; |
devi@0 | 271 |
devi@0 | 272 my %myenv = ( %Config, |
devi@0 | 273 host => $m, |
devi@0 | 274 dirs => "/root /home/".$Machines{$m}->{"user"}, |
devi@3 | 275 lablogs => $Config{"path_lablogs"}."/". |
devi@0 | 276 $XMLClass->{"course"}."/". |
devi@0 | 277 $XMLClass->{"date"}."/". |
devi@0 | 278 "$m", |
devi@0 | 279 lab => $arg, |
devi@0 | 280 |
devi@0 | 281 email => $Machines{$m}->{"student"}->{"email"}, |
devi@0 | 282 company => $Machines{$m}->{"student"}->{"company"}, |
devi@0 | 283 center => $XMLClass->{"center"}, |
devi@0 | 284 course => $XMLClass->{"course"}, |
devi@0 | 285 date => $XMLClass->{"date"}, |
devi@0 | 286 name => $Machines{$m}->{"name"}, |
devi@0 | 287 coursepath => $XMLCourse->{"path"}, |
devi@0 | 288 |
devi@0 | 289 ); |
devi@0 | 290 if (grep { $_ eq $command} keys %Scripts) { |
devi@0 | 291 $_=$Scripts{"$command"}; |
devi@0 | 292 s/\$(\w+)/$myenv{$1}/ge; |
devi@0 | 293 open(SHELL, "|/bin/sh -s"); |
devi@0 | 294 binmode SHELL, ":utf8"; |
devi@0 | 295 print SHELL $_; |
devi@0 | 296 close (SHELL); |
devi@0 | 297 } |
devi@0 | 298 else { |
devi@0 | 299 my $res = `ssh $Config{"ssh_user"}\@$m $command`; |
devi@0 | 300 if ($res) { |
devi@0 | 301 my $count = ($res =~ s/(^)/$m: /mg); |
devi@0 | 302 print $res; |
devi@0 | 303 print "\n" if ($count > 1); |
devi@0 | 304 } |
devi@0 | 305 } |
devi@0 | 306 } |
devi@0 | 307 $i++; |
devi@0 | 308 } |
devi@0 | 309 } |
devi@0 | 310 |
devi@0 | 311 |
devi@3 | 312 |
devi@3 | 313 =cut comment |
devi@3 | 314 |
devi@3 | 315 lm report |
devi@3 | 316 |
devi@3 | 317 Построить html представление для журналов текущего класса. |
devi@3 | 318 Для построения используется скрипт l3-report. |
devi@3 | 319 |
devi@3 | 320 =cut |
devi@3 | 321 |
devi@0 | 322 sub lm_report |
devi@0 | 323 { |
devi@0 | 324 |
devi@3 | 325 my $webdir = $Config{"path_web"}; |
devi@3 | 326 my $course=$XMLClass->{"course"}; |
devi@3 | 327 my $date=$XMLClass->{"date"}; |
devi@3 | 328 my $encoding=$XMLClass->{"charset"}; |
devi@0 | 329 |
devi@4 | 330 my $center = $XMLClass->{"center"}; |
devi@4 | 331 my $instructor = $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"}; |
devi@4 | 332 my $course_name = $XMLCourse->{"fullname"}[0]; |
devi@4 | 333 |
devi@5 | 334 |
devi@5 | 335 # Собственно журналы |
devi@5 | 336 |
devi@5 | 337 for my $student (@{$XMLClass->{"student"}}) { |
devi@5 | 338 my $user = $student->{"user"}; |
devi@5 | 339 my $hostname = $student->{"host"}; |
devi@6 | 340 my $encoding = $student->{"charset"}; |
devi@6 | 341 my $student_name = $student->{"firstname"}." ".$student->{"surname"}; |
devi@5 | 342 |
devi@5 | 343 system("mkdir -p $webdir/$date/$hostname"); |
devi@5 | 344 system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname"); |
devi@5 | 345 system($Config{"l3-report"}. |
devi@5 | 346 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user". |
devi@5 | 347 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ". |
devi@5 | 348 $Config{"path_lablogs"}."/$course/$date/$hostname/root". |
devi@5 | 349 " --output $webdir/$date/$hostname/$user.html". |
devi@6 | 350 " --course-name '$course_name'". |
devi@6 | 351 " --course-code '$course'". |
devi@6 | 352 " --course-date '$date'". |
devi@6 | 353 " --course-center '$center'". |
devi@6 | 354 " --course-student '$student_name'". |
devi@6 | 355 " --course-trainer '$instructor'". |
devi@5 | 356 " --encoding $encoding" |
devi@5 | 357 ); |
devi@5 | 358 system($Config{"l3-report"}. |
devi@5 | 359 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root". |
devi@5 | 360 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ". |
devi@5 | 361 " --output $webdir/$date/$hostname/root.html". |
devi@6 | 362 " --course-name '$course_name'". |
devi@6 | 363 " --course-code '$course'". |
devi@6 | 364 " --course-date '$date'". |
devi@6 | 365 " --course-center '$center'". |
devi@6 | 366 " --course-student '$student_name'". |
devi@6 | 367 " --course-trainer '$instructor'". |
devi@5 | 368 " --encoding $encoding" |
devi@5 | 369 ); |
devi@5 | 370 } |
devi@5 | 371 |
devi@4 | 372 # Индекс для данного класса |
devi@4 | 373 |
devi@4 | 374 my $head; |
devi@4 | 375 |
devi@4 | 376 $head="Журналы лабораторных работ"; |
devi@4 | 377 open(HTML, ">$webdir/$date/index.html") |
devi@4 | 378 or die "Can't open $webdir/$date/index.html for writing"; |
devi@4 | 379 binmode HTML, ":utf8"; |
devi@4 | 380 print HTML <<HEAD; |
devi@4 | 381 <html> |
devi@4 | 382 <head> |
devi@4 | 383 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> |
devi@4 | 384 <title>$head</title> |
devi@4 | 385 </head> |
devi@4 | 386 <body> |
devi@4 | 387 <h1>$head</h1> |
devi@4 | 388 <p> |
devi@4 | 389 Курс: $course_name ($course)<br/> |
devi@4 | 390 Начало: $date<br/> |
devi@4 | 391 Учебный центр: $center <br/> |
devi@4 | 392 Инструктор: $instructor <br/> |
devi@4 | 393 </p> |
devi@4 | 394 <table> |
devi@4 | 395 HEAD |
devi@4 | 396 for my $student (@{$XMLClass->{"student"}}) { |
devi@4 | 397 my $user = $student->{"user"}; |
devi@4 | 398 my $hostname = $student->{"host"}; |
devi@4 | 399 print HTML "<tr>\n"; |
devi@4 | 400 print HTML "<td>",$student->{"firstname"}," ",$student->{"surname"},"</td>\n"; |
devi@4 | 401 print HTML "<td>",$hostname,"</td>\n"; |
devi@4 | 402 print HTML "<td><a href=\"$hostname/$user.html\">",$user,"</td>\n"; |
devi@4 | 403 print HTML "<td><a href=\"$hostname/root.html\">","root","</td>\n"; |
devi@4 | 404 print HTML "</tr>\n"; |
devi@4 | 405 } |
devi@4 | 406 print HTML <<TAIL; |
devi@4 | 407 </table> |
devi@4 | 408 </html> |
devi@4 | 409 TAIL |
devi@4 | 410 close (HTML); |
devi@4 | 411 |
devi@4 | 412 |
devi@4 | 413 |
devi@0 | 414 } |
devi@0 | 415 |
devi@0 | 416 sub load_run |
devi@0 | 417 { |
devi@0 | 418 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"}; |
devi@0 | 419 open (RUN, $runfile) |
devi@0 | 420 or return; |
devi@0 | 421 while (<RUN>) { |
devi@0 | 422 chomp; |
devi@0 | 423 my ($var, $val) = split /\s+/,$_,2; |
devi@0 | 424 $Run{$var}=$val; |
devi@0 | 425 } |
devi@0 | 426 close (RUN); |
devi@0 | 427 } |
devi@0 | 428 |
devi@0 | 429 sub save_run |
devi@0 | 430 { |
devi@0 | 431 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"}; |
devi@0 | 432 open (RN, "$runfile") |
devi@0 | 433 or die "Can't save running state to $runfile"; |
devi@0 | 434 for my $var (keys %Run) { |
devi@0 | 435 print RN $var,"\t",$Run{$var},"\n"; |
devi@0 | 436 } |
devi@0 | 437 close (RN); |
devi@0 | 438 } |
devi@0 | 439 |
devi@0 | 440 sub print_log |
devi@0 | 441 { |
devi@0 | 442 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"}; |
devi@0 | 443 open (LOG, ">>$logfile") |
devi@0 | 444 or die "Can't open logfile $logfile for writing"; |
devi@0 | 445 print LOG @_; |
devi@0 | 446 close (LOG); |
devi@0 | 447 } |
devi@0 | 448 |
devi@0 | 449 |
devi@0 | 450 sub print_usage_info |
devi@0 | 451 { |
devi@0 | 452 print "Usage:\n\n\t$0 [host-list] command\n"; |
devi@0 | 453 while (<USAGE>) { |
devi@0 | 454 print $_; |
devi@0 | 455 } |
devi@0 | 456 } |
devi@0 | 457 |
devi@0 | 458 __USAGE__ |
devi@0 | 459 |
devi@0 | 460 Commands: |
devi@0 | 461 |
devi@0 | 462 next -- next lab |
devi@0 | 463 prev -- prev lab |
devi@0 | 464 set LAB -- set current lab to LAB |
devi@0 | 465 start -- start this day training |
devi@0 | 466 stop -- stop this day training |
devi@0 | 467 show hosts -- show available hosts in the class |
devi@0 | 468 show labs -- show available labs in the course |
devi@0 | 469 do COMMAND -- do specified command on the hosts of hostlist |
devi@0 | 470 report -- generate XML/HTML reports |
devi@0 | 471 |
devi@0 | 472 |
devi@0 | 473 do commands: |
devi@0 | 474 |
devi@0 | 475 install [PROFILE] -- install profile |
devi@0 | 476 |
devi@0 | 477 Host list: |
devi@0 | 478 |
devi@0 | 479 @N -- machine N |
devi@0 | 480 @N1-N2 -- all of the machines from N1 to N2 |
devi@0 | 481 @N1,N2,N3 -- machine N1, N2 and N3 |
devi@0 | 482 |
devi@0 | 483 N* is numbers or domain names of the machines. |
devi@0 | 484 |
devi@0 | 485 If host list is not specified, |
devi@0 | 486 command is executed on all of the machines |
devi@0 | 487 |
devi@0 | 488 |
devi@0 | 489 |
devi@0 | 490 __SCRIPTS__ |
devi@0 | 491 ###install |
devi@0 | 492 cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"' |
devi@0 | 493 |
devi@0 | 494 ###install-lm |
devi@0 | 495 cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs |
devi@0 | 496 |
devi@0 | 497 ###copy-lablogs |
devi@0 | 498 for i in $dirs |
devi@0 | 499 do |
devi@0 | 500 mkdir -p $lablogs/${i##*/} |
devi@0 | 501 scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/} |
devi@0 | 502 done |
devi@0 | 503 |
devi@0 | 504 ###setlab |
devi@0 | 505 for i in $dirs |
devi@0 | 506 do |
devi@0 | 507 echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab" |
devi@0 | 508 done |
devi@0 | 509 |
devi@0 | 510 ###makeout |
devi@0 | 511 common=$course-$date |
devi@0 | 512 personal=$course-$date-$email |
devi@0 | 513 mkdir -p $outpath/${common}/{Lablogs,Docs} |
devi@0 | 514 mkdir -p $outpath/${personal}/{Course,Files} |
devi@0 | 515 cd $outpath/${personal} |
devi@0 | 516 ln -s ../${common}/Lablogs . |
devi@0 | 517 ln -s ../${common}/Docs . |
devi@0 | 518 cd ~- |
devi@15 | 519 export UG_PERSONAL=$outpath/${personal}/Course |
devi@0 | 520 export UG_CENTER="$center" |
devi@0 | 521 export UG_COURSE="$course" |
devi@0 | 522 export UG_DATE="$date" |
devi@0 | 523 export UG_STUDENT="$name" |
devi@0 | 524 export UG_COMPANY="$company" |
devi@0 | 525 cd $coursepath; make personal; cd ~- |
devi@0 | 526 |
devi@0 | 527 ###watch |
devi@0 | 528 cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker |