lilalo

view lm @ 4:774de5c1ad00

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