lilalo

view lm @ 1:ff93ad94d73b

LiLaLo -- Live Lab Log
(L3)

Система автоматического ведения журналов
и автоматизированного управления ходом
лабораторных работ.
author devi
date Sun May 22 16:29:55 2005 +0300 (2005-05-22)
parents
children 6c1d2b9f45e7
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 "path_labmaker" => "/var/labmaker/",
24 "path_classes" => "/var/labmaker/classes/",
25 "lablogs_path" => "/var/labmaker/lablogs/",
26 "courses_path" => "/var/labmaker/courses/",
27 "outpath" => "/var/labmaker/out/",
29 # Файлы
30 "runfile" => "lm.run",
31 "logfile" => "lm.log",
33 "class" => "class", # Имя файла класса
34 "class_suffix" => ".xml", # Cуффикс файла класса
36 "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub",
37 "lmssh" => "./lm-ssh",
38 "lminstall" => "./lm-install",
39 "ssh_user" => "r",
40 );
42 our %Run = (
43 "lab" => ""
44 );
46 our %Scripts;
48 sub load_class;
49 sub load_config;
50 sub load_course;
51 sub load_scripts;
53 sub lm_next;
54 sub lm_prev;
55 sub lm_start;
56 sub lm_stop;
57 sub lm_set;
58 sub lm_do;
59 sub lm_report;
60 sub lm_show_hosts;
61 sub lm_show_labs;
63 sub load_run;
64 sub save_run;
65 sub print_log;
66 sub print_usage_info;
67 sub main();
69 main();
71 sub main()
72 {
73 binmode STDOUT, ":utf8";
75 if (! @ARGV) {
76 print_usage_info();
77 exit(0);
78 }
80 load_config;
81 load_run;
82 load_scripts;
83 load_class;
84 load_course;
86 my $arg = join " ", @ARGV;
88 # Getting @SelectedMachines if any
89 if ($arg =~ s/@(.*?)\s//) {
90 my $machines = $1;
91 my @list = split /,/, $machines;
92 for my $interval (@list) {
93 my ($first, $last) = split /-/, $interval;
95 push @SelectedMachines, $first;
96 while ($first < $last) {
97 push @SelectedMachines, ++$first;
98 }
99 }
100 }
102 # Choose command to do
103 switch ($arg) {
104 case "next" { lm_next }
105 case "prev" { lm_prev }
106 case /set / { $arg =~ /set (.*)/; lm_set $1 }
107 case "report" { lm_report }
108 case "start" { lm_start }
109 case "stop" { lm_stop }
110 case "show hosts" { lm_show_hosts }
111 case "show labs" { lm_show_labs }
112 case /do / { $arg =~ /do (.*)/; lm_do "$1" }
113 else { print_usage_info() }
114 }
115 save_run;
116 exit(0);
117 }
119 sub load_scripts
120 {
121 local $/;
122 $_=<SCRIPTS>;
123 %Scripts = ("empty-element", split (/###(.*)\n/));
124 delete($Scripts{"empty-element"});
125 }
127 sub load_config
128 {
129 my %file_config;
130 my %argv_config;
131 #read_config_file(\%file_config, $Config_File);
132 GetOptions(\%argv_config, map "$_=s", keys %Config);
133 %Config = (%Config, %file_config, %argv_config);
134 }
136 sub load_course
137 {
138 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )
139 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
140 # print Dumper($XMLCourse);
141 for my $lab (@{$XMLCourse->{"module"}}) {
142 push @Labs, $lab->{"code"};
143 }
144 }
146 sub load_class
147 {
148 my $classfile =
149 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
150 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )
151 or die "Can't open file of the class ",$classfile,"\n";
153 for my $student (@{$XMLClass->{"student"}}) {
154 $Machines{$student->{"host"}} = {
155 "name" => "$student->{firstname} $student->{surname}",
156 "user" => "$student->{user}",
157 "student" => $student,
158 }
159 }
160 # print Dumper($XMLClass);
161 # print Dumper(\%Machines);
162 }
165 sub lm_next
166 {
167 for(my $i=0; $i<=$#Labs; $i++){
168 if ( $Labs[$i] eq $Run{"lab"} ) {
169 if ($i < $#Labs) {
170 lm_set($Labs[$i+1]);
171 return ;
172 } else {
173 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
174 }
175 }
177 }
178 die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
179 }
181 sub lm_prev
182 # Switch to previous lab
183 {
184 for(my $i=0; $i<=$#Labs; $i++){
185 if ( $Labs[$i] eq $Run{"lab"} ) {
186 if ($i > 0) {
187 lm_set($Labs[$i-1]);
188 return ;
189 } else {
190 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
191 }
192 }
194 }
195 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
196 }
198 sub lm_set
199 # Switch to $_[0] lab
200 # FIXME
201 {
202 my $lab = shift;
203 print "Current lab is $lab\n";
204 $Run{"lab"} = "$lab";
205 lm_do "setlab", $lab;
206 }
209 sub lm_start
210 # Start new training day
211 {
212 print_log(`date`." STARTED\n");
213 if ($Run{"lab"}) {
214 lm_next;
215 }
216 else
217 {
218 # First lab in the course
219 lm_set($Labs[0]);
220 }
221 }
223 sub lm_stop
224 # Stop this training day
225 {
226 print_log(`date`." STOPPED\n");
227 }
230 sub lm_show_hosts
231 # Show hosts used to run a commands
232 {
233 my $i=1;
234 for my $m (sort keys %Machines) {
235 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
236 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
237 }
238 $i++;
239 }
240 }
242 sub lm_show_labs
243 # Show hosts used to run a commands
244 {
245 my $i=1;
246 for my $lab (@Labs) {
247 print $lab;
248 print "*" if $lab eq $Run{"lab"};
249 print "\n";
250 }
251 }
253 sub lm_do
254 # Do the $_[0] command on all of the hosts
255 {
256 my $command = shift;
257 my $arg = join " ", @_;
258 my $i=1;
259 for my $m (sort keys %Machines) {
260 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
261 print "$m:\n" if $Config{"show_host"} =~ /y/i;
263 my %myenv = ( %Config,
264 host => $m,
265 dirs => "/root /home/".$Machines{$m}->{"user"},
266 lablogs => $Config{"lablogs_path"}."/".
267 $XMLClass->{"course"}."/".
268 $XMLClass->{"date"}."/".
269 "$m",
270 lab => $arg,
272 email => $Machines{$m}->{"student"}->{"email"},
273 company => $Machines{$m}->{"student"}->{"company"},
274 center => $XMLClass->{"center"},
275 course => $XMLClass->{"course"},
276 date => $XMLClass->{"date"},
277 name => $Machines{$m}->{"name"},
278 coursepath => $XMLCourse->{"path"},
280 );
281 if (grep { $_ eq $command} keys %Scripts) {
282 $_=$Scripts{"$command"};
283 s/\$(\w+)/$myenv{$1}/ge;
284 open(SHELL, "|/bin/sh -s");
285 binmode SHELL, ":utf8";
286 print SHELL $_;
287 close (SHELL);
288 }
289 else {
290 my $res = `ssh $Config{"ssh_user"}\@$m $command`;
291 if ($res) {
292 my $count = ($res =~ s/(^)/$m: /mg);
293 print $res;
294 print "\n" if ($count > 1);
295 }
296 }
297 }
298 $i++;
299 }
300 }
303 sub lm_report
304 {
306 print "Not implemented yet\n";
307 exit(1);
309 =cut comment
311 Дальше идут скрипты, код которых нужно реализовать здесь.
312 Как минимум.
314 =cut
316 my $lm_script_make_report_web = <<'SCRIPT';
318 #!/bin/sh
320 ####cd /home/devi/lm
321 ./lm do copy-lablogs
322 ##./lm-report --input /home/murk/.labmaker --output /var/www/lm/murk.html
323 ##exit
325 COURSE=ug-h
326 DATE=2005-04-25
327 SUFF=".linux.nt"
328 #MACHINES="m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15"
329 #MACHINES="m1 m2 m3 m4 m5 m6 m7 f1 f2 f3 f4 f5"
330 MACHINES="m01 m02 m03 m04 m05 m06 m07 m08"
331 #MACHINES="m1"
332 USERS="user root"
333 WEBDIR=/var/www/lm
335 for u in $USERS
336 do
337 for m in $MACHINES
338 do
339 e=utf-8
340 [ "${m##f}" = "$m" ] || e=koi8-r
341 #e=koi8-r
342 mkdir -p $WEBDIR/$DATE/$m
343 cp share/*.ico share/*.css $WEBDIR/$m
344 #echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
345 ./lm-report\
346 --input Lablogs/$COURSE/$DATE/$m$SUFF/$u/ \
347 --diffs "Lablogs/$COURSE/$DATE/$m$SUFF/$u/ Lablogs/$COURSE/$DATE/$m$SUFF/root/"\
348 --output /var/www/lm/$DATE/$m/$u.html \
349 --encoding $e
350 done
351 done
354 SCRIPT
356 my $lm_script_make_report_all = <<'SCRIPT';
358 #!/bin/sh
359 WEBDIR=/var/www/lm
361 find . -type d -maxdepth 5 -mindepth 5 |\
362 while read dir
363 do
364 subdir=${dir##Lablogs/}
365 e=utf-8
366 echo $dir | grep -qi bsd && e=koi8-r
367 echo $dir | grep -qi /f && e=koi8-r
369 mkdir -p $WEBDIR/${subdir%/*}
370 cp share/*.ico share/*.css $WEBDIR/${subdir%/*}
371 #echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
372 ./lm-report\
373 --input $dir \
374 --diffs "${dir%/user}/root $dir"\
375 --output $WEBDIR/$subdir.html \
376 --encoding $e
377 done
379 SCRIPT
380 }
382 sub load_run
383 {
384 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
385 open (RUN, $runfile)
386 or return;
387 while (<RUN>) {
388 chomp;
389 my ($var, $val) = split /\s+/,$_,2;
390 $Run{$var}=$val;
391 }
392 close (RUN);
393 }
395 sub save_run
396 {
397 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
398 open (RN, "$runfile")
399 or die "Can't save running state to $runfile";
400 for my $var (keys %Run) {
401 print RN $var,"\t",$Run{$var},"\n";
402 }
403 close (RN);
404 }
406 sub print_log
407 {
408 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
409 open (LOG, ">>$logfile")
410 or die "Can't open logfile $logfile for writing";
411 print LOG @_;
412 close (LOG);
413 }
416 sub print_usage_info
417 {
418 print "Usage:\n\n\t$0 [host-list] command\n";
419 while (<USAGE>) {
420 print $_;
421 }
422 }
424 __USAGE__
426 Commands:
428 next -- next lab
429 prev -- prev lab
430 set LAB -- set current lab to LAB
431 start -- start this day training
432 stop -- stop this day training
433 show hosts -- show available hosts in the class
434 show labs -- show available labs in the course
435 do COMMAND -- do specified command on the hosts of hostlist
436 report -- generate XML/HTML reports
439 do commands:
441 install [PROFILE] -- install profile
443 Host list:
445 @N -- machine N
446 @N1-N2 -- all of the machines from N1 to N2
447 @N1,N2,N3 -- machine N1, N2 and N3
449 N* is numbers or domain names of the machines.
451 If host list is not specified,
452 command is executed on all of the machines
456 __SCRIPTS__
457 ###install
458 cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
460 ###install-lm
461 cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
463 ###copy-lablogs
464 for i in $dirs
465 do
466 mkdir -p $lablogs/${i##*/}
467 scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
468 done
470 ###setlab
471 for i in $dirs
472 do
473 echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
474 done
476 ###makeout
477 common=$course-$date
478 personal=$course-$date-$email
479 mkdir -p $outpath/${common}/{Lablogs,Docs}
480 mkdir -p $outpath/${personal}/{Course,Files}
481 cd $outpath/${personal}
482 ln -s ../${common}/Lablogs .
483 ln -s ../${common}/Docs .
484 cd ~-
485 export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
486 export UG_CENTER="$center"
487 export UG_COURSE="$course"
488 export UG_DATE="$date"
489 export UG_STUDENT="$name"
490 export UG_COMPANY="$company"
491 cd $coursepath; make personal; cd ~-
493 ###watch
494 cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker