lilalo

view lm @ 66:563e3ee69ce8

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