lilalo

view lm @ 3:6c1d2b9f45e7

Добавил команду lm report.

Строит html-представление журналов
для заданного класса.
Нужно сделать поддержку опций GetOpt::Long
и тогда эту же команду можно будет использовать
для построения всех журналов в репозитории.
author devi
date Tue May 24 13:00:28 2005 +0300 (2005-05-24)
parents 18b21f6918f0
children 774de5c1ad00
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;
11 our $XMLClass;
12 our $XMLCourse;
13 our @Labs;
15 our %Machines; # Machines list from class.xml
16 our @SelectedMachines; # Machines list given as the command line argument
18 our $Config_File = "labmaker.conf";
19 our %Config = (
20 "show_host" => "no",
22 # Вспомогательные программы
23 "l3-report" => "./lm-report",
25 # Каталоги
26 "path_labmaker" => "/var/labmaker/",
27 "path_classes" => "/var/labmaker/classes/",
28 "path_lablogs" => "/var/labmaker/lablogs/",
29 "courses_path" => "/var/labmaker/courses/",
30 "outpath" => "/var/labmaker/out/",
31 "path_web" => "/var/www/l3", # Путь к web-отчётам
32 "path_share" => "./share/", # Путь к web-отчётам
34 # Файлы
35 "runfile" => "lm.run",
36 "logfile" => "lm.log",
38 "class" => "class", # Имя файла класса
39 "class_suffix" => ".xml", # Cуффикс файла класса
41 "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub",
42 "lmssh" => "./lm-ssh",
43 "lminstall" => "./lm-install",
44 "ssh_user" => "r",
45 );
47 our %Run = (
48 "lab" => ""
49 );
51 our %Scripts;
53 sub load_class;
54 sub load_config;
55 sub load_course;
56 sub load_scripts;
58 sub lm_next;
59 sub lm_prev;
60 sub lm_start;
61 sub lm_stop;
62 sub lm_set;
63 sub lm_do;
64 sub lm_report;
65 sub lm_show_hosts;
66 sub lm_show_labs;
68 sub load_run;
69 sub save_run;
70 sub print_log;
71 sub print_usage_info;
72 sub main();
74 main();
76 sub main()
77 {
78 binmode STDOUT, ":utf8";
80 if (! @ARGV) {
81 print_usage_info();
82 exit(0);
83 }
85 load_config;
86 load_run;
87 load_scripts;
88 load_class;
89 load_course;
91 my $arg = join " ", @ARGV;
93 # Getting @SelectedMachines if any
94 if ($arg =~ s/@(.*?)\s//) {
95 my $machines = $1;
96 my @list = split /,/, $machines;
97 for my $interval (@list) {
98 my ($first, $last) = split /-/, $interval;
100 push @SelectedMachines, $first;
101 while ($first < $last) {
102 push @SelectedMachines, ++$first;
103 }
104 }
105 }
107 # Choose command to do
108 switch ($arg) {
109 case "next" { lm_next }
110 case "prev" { lm_prev }
111 case /set / { $arg =~ /set (.*)/; lm_set $1 }
112 case "report" { lm_report }
113 case "start" { lm_start }
114 case "stop" { lm_stop }
115 case "show hosts" { lm_show_hosts }
116 case "show labs" { lm_show_labs }
117 case /do / { $arg =~ /do (.*)/; lm_do "$1" }
118 else { print_usage_info() }
119 }
120 save_run;
121 exit(0);
122 }
124 sub load_scripts
125 {
126 local $/;
127 $_=<SCRIPTS>;
128 %Scripts = ("empty-element", split (/###(.*)\n/));
129 delete($Scripts{"empty-element"});
130 }
132 sub load_config
133 {
134 my %file_config;
135 my %argv_config;
136 #read_config_file(\%file_config, $Config_File);
137 GetOptions(\%argv_config, map "$_=s", keys %Config);
138 %Config = (%Config, %file_config, %argv_config);
139 }
141 sub load_course
142 {
143 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )
144 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
145 # print Dumper($XMLCourse);
146 for my $lab (@{$XMLCourse->{"module"}}) {
147 push @Labs, $lab->{"code"};
148 }
149 }
151 sub load_class
152 {
153 my $classfile =
154 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
155 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )
156 or die "Can't open file of the class ",$classfile,"\n";
158 for my $student (@{$XMLClass->{"student"}}) {
159 $Machines{$student->{"host"}} = {
160 "name" => "$student->{firstname} $student->{surname}",
161 "user" => "$student->{user}",
162 "student" => $student,
163 }
164 }
165 # print Dumper($XMLClass);
166 # print Dumper(\%Machines);
167 }
170 sub lm_next
171 {
172 for(my $i=0; $i<=$#Labs; $i++){
173 if ( $Labs[$i] eq $Run{"lab"} ) {
174 if ($i < $#Labs) {
175 lm_set($Labs[$i+1]);
176 return ;
177 } else {
178 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
179 }
180 }
182 }
183 die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
184 }
186 sub lm_prev
187 # Switch to previous lab
188 {
189 for(my $i=0; $i<=$#Labs; $i++){
190 if ( $Labs[$i] eq $Run{"lab"} ) {
191 if ($i > 0) {
192 lm_set($Labs[$i-1]);
193 return ;
194 } else {
195 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
196 }
197 }
199 }
200 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
201 }
203 sub lm_set
204 # Switch to $_[0] lab
205 # FIXME
206 {
207 my $lab = shift;
208 print "Current lab is $lab\n";
209 $Run{"lab"} = "$lab";
210 lm_do "setlab", $lab;
211 }
214 sub lm_start
215 # Start new training day
216 {
217 print_log(`date`." STARTED\n");
218 if ($Run{"lab"}) {
219 lm_next;
220 }
221 else
222 {
223 # First lab in the course
224 lm_set($Labs[0]);
225 }
226 }
228 sub lm_stop
229 # Stop this training day
230 {
231 print_log(`date`." STOPPED\n");
232 }
235 sub lm_show_hosts
236 # Show hosts used to run a commands
237 {
238 my $i=1;
239 for my $m (sort keys %Machines) {
240 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
241 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
242 }
243 $i++;
244 }
245 }
247 sub lm_show_labs
248 # Show hosts used to run a commands
249 {
250 my $i=1;
251 for my $lab (@Labs) {
252 print $lab;
253 print "*" if $lab eq $Run{"lab"};
254 print "\n";
255 }
256 }
258 sub lm_do
259 # Do the $_[0] command on all of the hosts
260 {
261 my $command = shift;
262 my $arg = join " ", @_;
263 my $i=1;
264 for my $m (sort keys %Machines) {
265 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
266 print "$m:\n" if $Config{"show_host"} =~ /y/i;
268 my %myenv = ( %Config,
269 host => $m,
270 dirs => "/root /home/".$Machines{$m}->{"user"},
271 lablogs => $Config{"path_lablogs"}."/".
272 $XMLClass->{"course"}."/".
273 $XMLClass->{"date"}."/".
274 "$m",
275 lab => $arg,
277 email => $Machines{$m}->{"student"}->{"email"},
278 company => $Machines{$m}->{"student"}->{"company"},
279 center => $XMLClass->{"center"},
280 course => $XMLClass->{"course"},
281 date => $XMLClass->{"date"},
282 name => $Machines{$m}->{"name"},
283 coursepath => $XMLCourse->{"path"},
285 );
286 if (grep { $_ eq $command} keys %Scripts) {
287 $_=$Scripts{"$command"};
288 s/\$(\w+)/$myenv{$1}/ge;
289 open(SHELL, "|/bin/sh -s");
290 binmode SHELL, ":utf8";
291 print SHELL $_;
292 close (SHELL);
293 }
294 else {
295 my $res = `ssh $Config{"ssh_user"}\@$m $command`;
296 if ($res) {
297 my $count = ($res =~ s/(^)/$m: /mg);
298 print $res;
299 print "\n" if ($count > 1);
300 }
301 }
302 }
303 $i++;
304 }
305 }
309 =cut comment
311 lm report
313 Построить html представление для журналов текущего класса.
314 Для построения используется скрипт l3-report.
316 =cut
318 sub lm_report
319 {
321 my $webdir = $Config{"path_web"};
322 my $course=$XMLClass->{"course"};
323 my $date=$XMLClass->{"date"};
324 my $encoding=$XMLClass->{"charset"};
326 print "date=$date\n";
328 for my $student (@{$XMLClass->{"student"}}) {
329 my $user = $student->{"user"};
330 my $hostname = $student->{"host"};
331 my $encoding = $student->{"encoding"};
333 system("mkdir -p $webdir/$date/$hostname");
334 system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname");
335 system($Config{"l3-report"}.
336 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user".
337 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ".
338 $Config{"path_lablogs"}."/$course/$date/$hostname/root".
339 " --output $webdir/$date/$hostname/$user.html".
340 " --encoding $encoding"
341 );
342 system($Config{"l3-report"}.
343 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root".
344 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ".
345 " --output $webdir/$date/$hostname/root.html".
346 " --encoding $encoding"
347 );
348 }
349 }
351 sub load_run
352 {
353 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
354 open (RUN, $runfile)
355 or return;
356 while (<RUN>) {
357 chomp;
358 my ($var, $val) = split /\s+/,$_,2;
359 $Run{$var}=$val;
360 }
361 close (RUN);
362 }
364 sub save_run
365 {
366 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
367 open (RN, "$runfile")
368 or die "Can't save running state to $runfile";
369 for my $var (keys %Run) {
370 print RN $var,"\t",$Run{$var},"\n";
371 }
372 close (RN);
373 }
375 sub print_log
376 {
377 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
378 open (LOG, ">>$logfile")
379 or die "Can't open logfile $logfile for writing";
380 print LOG @_;
381 close (LOG);
382 }
385 sub print_usage_info
386 {
387 print "Usage:\n\n\t$0 [host-list] command\n";
388 while (<USAGE>) {
389 print $_;
390 }
391 }
393 __USAGE__
395 Commands:
397 next -- next lab
398 prev -- prev lab
399 set LAB -- set current lab to LAB
400 start -- start this day training
401 stop -- stop this day training
402 show hosts -- show available hosts in the class
403 show labs -- show available labs in the course
404 do COMMAND -- do specified command on the hosts of hostlist
405 report -- generate XML/HTML reports
408 do commands:
410 install [PROFILE] -- install profile
412 Host list:
414 @N -- machine N
415 @N1-N2 -- all of the machines from N1 to N2
416 @N1,N2,N3 -- machine N1, N2 and N3
418 N* is numbers or domain names of the machines.
420 If host list is not specified,
421 command is executed on all of the machines
425 __SCRIPTS__
426 ###install
427 cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
429 ###install-lm
430 cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
432 ###copy-lablogs
433 for i in $dirs
434 do
435 mkdir -p $lablogs/${i##*/}
436 scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
437 done
439 ###setlab
440 for i in $dirs
441 do
442 echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
443 done
445 ###makeout
446 common=$course-$date
447 personal=$course-$date-$email
448 mkdir -p $outpath/${common}/{Lablogs,Docs}
449 mkdir -p $outpath/${personal}/{Course,Files}
450 cd $outpath/${personal}
451 ln -s ../${common}/Lablogs .
452 ln -s ../${common}/Docs .
453 cd ~-
454 export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
455 export UG_CENTER="$center"
456 export UG_COURSE="$course"
457 export UG_DATE="$date"
458 export UG_STUDENT="$name"
459 export UG_COMPANY="$company"
460 cd $coursepath; make personal; cd ~-
462 ###watch
463 cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker