lilalo

annotate lm @ 80:d28dda8ea18f

1)
Изменён формат имени diff-файлов.
Теперь в имени присутствует только название сессии, время и имя файла.

2)
Можно просмотреть отдельную сессию.
Для этого нужно щёлкнуть по блоку сессии в журнале

3)
Исправлена ошибка с таблицей новых команд в последнем дне.
Раньше она просто не показывалась

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