lilalo

view lm @ 5:7d4d067f9823

Добавился параметр --classfile
для указания точного пути к файлу класса
author devi
date Tue May 24 13:56:12 2005 +0300 (2005-05-24)
parents 774de5c1ad00
children a0f30dd46d1a
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уффикс файла класса
41 "classfile" => "",
43 "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub",
44 "lmssh" => "./lm-ssh",
45 "lminstall" => "./lm-install",
46 "ssh_user" => "r",
47 );
49 our %Run = (
50 "lab" => ""
51 );
53 our %Scripts;
55 sub load_class;
56 sub load_config;
57 sub load_course;
58 sub load_scripts;
60 sub lm_next;
61 sub lm_prev;
62 sub lm_start;
63 sub lm_stop;
64 sub lm_set;
65 sub lm_do;
66 sub lm_report;
67 sub lm_show_hosts;
68 sub lm_show_labs;
70 sub load_run;
71 sub save_run;
72 sub print_log;
73 sub print_usage_info;
74 sub main();
76 main();
78 sub main()
79 {
80 binmode STDOUT, ":utf8";
82 if (! @ARGV) {
83 print_usage_info();
84 exit(0);
85 }
87 load_config;
88 load_run;
89 load_scripts;
90 load_class;
91 load_course;
93 my $arg = join " ", @ARGV;
95 # Getting @SelectedMachines if any
96 if ($arg =~ s/@(.*?)\s//) {
97 my $machines = $1;
98 my @list = split /,/, $machines;
99 for my $interval (@list) {
100 my ($first, $last) = split /-/, $interval;
102 push @SelectedMachines, $first;
103 while ($first < $last) {
104 push @SelectedMachines, ++$first;
105 }
106 }
107 }
109 # Choose command to do
110 switch ($arg) {
111 case "next" { lm_next }
112 case "prev" { lm_prev }
113 case /set / { $arg =~ /set (.*)/; lm_set $1 }
114 case "report" { lm_report }
115 case "start" { lm_start }
116 case "stop" { lm_stop }
117 case "show hosts" { lm_show_hosts }
118 case "show labs" { lm_show_labs }
119 case /do / { $arg =~ /do (.*)/; lm_do "$1" }
120 else { print_usage_info() }
121 }
122 save_run;
123 exit(0);
124 }
126 sub load_scripts
127 {
128 local $/;
129 $_=<SCRIPTS>;
130 %Scripts = ("empty-element", split (/###(.*)\n/));
131 delete($Scripts{"empty-element"});
132 }
134 sub load_config
135 {
136 my %file_config;
137 my %argv_config;
138 #read_config_file(\%file_config, $Config_File);
139 GetOptions(\%argv_config, map "$_=s", keys %Config);
140 %Config = (%Config, %file_config, %argv_config);
141 }
143 sub load_course
144 {
145 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )
146 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
147 # print Dumper($XMLCourse);
148 for my $lab (@{$XMLCourse->{"module"}}) {
149 push @Labs, $lab->{"code"};
150 }
151 }
153 sub load_class
154 {
155 my $classfile =
156 $Config{"classfile"} ||
157 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
158 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )
159 or die "Can't open file of the class ",$classfile,"\n";
161 for my $student (@{$XMLClass->{"student"}}) {
162 $Machines{$student->{"host"}} = {
163 "name" => "$student->{firstname} $student->{surname}",
164 "user" => "$student->{user}",
165 "student" => $student,
166 }
167 }
168 # print Dumper($XMLClass);
169 # print Dumper(\%Machines);
170 }
173 sub lm_next
174 {
175 for(my $i=0; $i<=$#Labs; $i++){
176 if ( $Labs[$i] eq $Run{"lab"} ) {
177 if ($i < $#Labs) {
178 lm_set($Labs[$i+1]);
179 return ;
180 } else {
181 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
182 }
183 }
185 }
186 die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
187 }
189 sub lm_prev
190 # Switch to previous lab
191 {
192 for(my $i=0; $i<=$#Labs; $i++){
193 if ( $Labs[$i] eq $Run{"lab"} ) {
194 if ($i > 0) {
195 lm_set($Labs[$i-1]);
196 return ;
197 } else {
198 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
199 }
200 }
202 }
203 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
204 }
206 sub lm_set
207 # Switch to $_[0] lab
208 # FIXME
209 {
210 my $lab = shift;
211 print "Current lab is $lab\n";
212 $Run{"lab"} = "$lab";
213 lm_do "setlab", $lab;
214 }
217 sub lm_start
218 # Start new training day
219 {
220 print_log(`date`." STARTED\n");
221 if ($Run{"lab"}) {
222 lm_next;
223 }
224 else
225 {
226 # First lab in the course
227 lm_set($Labs[0]);
228 }
229 }
231 sub lm_stop
232 # Stop this training day
233 {
234 print_log(`date`." STOPPED\n");
235 }
238 sub lm_show_hosts
239 # Show hosts used to run a commands
240 {
241 my $i=1;
242 for my $m (sort keys %Machines) {
243 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
244 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
245 }
246 $i++;
247 }
248 }
250 sub lm_show_labs
251 # Show hosts used to run a commands
252 {
253 my $i=1;
254 for my $lab (@Labs) {
255 print $lab;
256 print "*" if $lab eq $Run{"lab"};
257 print "\n";
258 }
259 }
261 sub lm_do
262 # Do the $_[0] command on all of the hosts
263 {
264 my $command = shift;
265 my $arg = join " ", @_;
266 my $i=1;
267 for my $m (sort keys %Machines) {
268 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
269 print "$m:\n" if $Config{"show_host"} =~ /y/i;
271 my %myenv = ( %Config,
272 host => $m,
273 dirs => "/root /home/".$Machines{$m}->{"user"},
274 lablogs => $Config{"path_lablogs"}."/".
275 $XMLClass->{"course"}."/".
276 $XMLClass->{"date"}."/".
277 "$m",
278 lab => $arg,
280 email => $Machines{$m}->{"student"}->{"email"},
281 company => $Machines{$m}->{"student"}->{"company"},
282 center => $XMLClass->{"center"},
283 course => $XMLClass->{"course"},
284 date => $XMLClass->{"date"},
285 name => $Machines{$m}->{"name"},
286 coursepath => $XMLCourse->{"path"},
288 );
289 if (grep { $_ eq $command} keys %Scripts) {
290 $_=$Scripts{"$command"};
291 s/\$(\w+)/$myenv{$1}/ge;
292 open(SHELL, "|/bin/sh -s");
293 binmode SHELL, ":utf8";
294 print SHELL $_;
295 close (SHELL);
296 }
297 else {
298 my $res = `ssh $Config{"ssh_user"}\@$m $command`;
299 if ($res) {
300 my $count = ($res =~ s/(^)/$m: /mg);
301 print $res;
302 print "\n" if ($count > 1);
303 }
304 }
305 }
306 $i++;
307 }
308 }
312 =cut comment
314 lm report
316 Построить html представление для журналов текущего класса.
317 Для построения используется скрипт l3-report.
319 =cut
321 sub lm_report
322 {
324 my $webdir = $Config{"path_web"};
325 my $course=$XMLClass->{"course"};
326 my $date=$XMLClass->{"date"};
327 my $encoding=$XMLClass->{"charset"};
329 my $center = $XMLClass->{"center"};
330 my $instructor = $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"};
331 my $course_name = $XMLCourse->{"fullname"}[0];
334 # Собственно журналы
336 for my $student (@{$XMLClass->{"student"}}) {
337 my $user = $student->{"user"};
338 my $hostname = $student->{"host"};
339 my $encoding = $student->{"encoding"};
341 system("mkdir -p $webdir/$date/$hostname");
342 system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname");
343 system($Config{"l3-report"}.
344 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user".
345 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ".
346 $Config{"path_lablogs"}."/$course/$date/$hostname/root".
347 " --output $webdir/$date/$hostname/$user.html".
348 " --encoding $encoding"
349 );
350 system($Config{"l3-report"}.
351 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root".
352 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ".
353 " --output $webdir/$date/$hostname/root.html".
354 " --encoding $encoding"
355 );
356 }
358 # Индекс для данного класса
360 my $head;
362 $head="Журналы лабораторных работ";
363 open(HTML, ">$webdir/$date/index.html")
364 or die "Can't open $webdir/$date/index.html for writing";
365 binmode HTML, ":utf8";
366 print HTML <<HEAD;
367 <html>
368 <head>
369 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
370 <title>$head</title>
371 </head>
372 <body>
373 <h1>$head</h1>
374 <p>
375 Курс: $course_name ($course)<br/>
376 Начало: $date<br/>
377 Учебный центр: $center <br/>
378 Инструктор: $instructor <br/>
379 </p>
380 <table>
381 HEAD
382 for my $student (@{$XMLClass->{"student"}}) {
383 my $user = $student->{"user"};
384 my $hostname = $student->{"host"};
385 print HTML "<tr>\n";
386 print HTML "<td>",$student->{"firstname"}," ",$student->{"surname"},"</td>\n";
387 print HTML "<td>",$hostname,"</td>\n";
388 print HTML "<td><a href=\"$hostname/$user.html\">",$user,"</td>\n";
389 print HTML "<td><a href=\"$hostname/root.html\">","root","</td>\n";
390 print HTML "</tr>\n";
391 }
392 print HTML <<TAIL;
393 </table>
394 </html>
395 TAIL
396 close (HTML);
400 }
402 sub load_run
403 {
404 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
405 open (RUN, $runfile)
406 or return;
407 while (<RUN>) {
408 chomp;
409 my ($var, $val) = split /\s+/,$_,2;
410 $Run{$var}=$val;
411 }
412 close (RUN);
413 }
415 sub save_run
416 {
417 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
418 open (RN, "$runfile")
419 or die "Can't save running state to $runfile";
420 for my $var (keys %Run) {
421 print RN $var,"\t",$Run{$var},"\n";
422 }
423 close (RN);
424 }
426 sub print_log
427 {
428 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
429 open (LOG, ">>$logfile")
430 or die "Can't open logfile $logfile for writing";
431 print LOG @_;
432 close (LOG);
433 }
436 sub print_usage_info
437 {
438 print "Usage:\n\n\t$0 [host-list] command\n";
439 while (<USAGE>) {
440 print $_;
441 }
442 }
444 __USAGE__
446 Commands:
448 next -- next lab
449 prev -- prev lab
450 set LAB -- set current lab to LAB
451 start -- start this day training
452 stop -- stop this day training
453 show hosts -- show available hosts in the class
454 show labs -- show available labs in the course
455 do COMMAND -- do specified command on the hosts of hostlist
456 report -- generate XML/HTML reports
459 do commands:
461 install [PROFILE] -- install profile
463 Host list:
465 @N -- machine N
466 @N1-N2 -- all of the machines from N1 to N2
467 @N1,N2,N3 -- machine N1, N2 and N3
469 N* is numbers or domain names of the machines.
471 If host list is not specified,
472 command is executed on all of the machines
476 __SCRIPTS__
477 ###install
478 cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
480 ###install-lm
481 cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
483 ###copy-lablogs
484 for i in $dirs
485 do
486 mkdir -p $lablogs/${i##*/}
487 scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
488 done
490 ###setlab
491 for i in $dirs
492 do
493 echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
494 done
496 ###makeout
497 common=$course-$date
498 personal=$course-$date-$email
499 mkdir -p $outpath/${common}/{Lablogs,Docs}
500 mkdir -p $outpath/${personal}/{Course,Files}
501 cd $outpath/${personal}
502 ln -s ../${common}/Lablogs .
503 ln -s ../${common}/Docs .
504 cd ~-
505 export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
506 export UG_CENTER="$center"
507 export UG_COURSE="$course"
508 export UG_DATE="$date"
509 export UG_STUDENT="$name"
510 export UG_COMPANY="$company"
511 cd $coursepath; make personal; cd ~-
513 ###watch
514 cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker