lilalo

view lm @ 78:147fb109c012

Добавлена функция l3shot,
которая позволяет делать скриншот экрана,
для того чтобы он мог быть автоматически вставлен в lablog
author devi
date Sun Feb 19 14:36:33 2006 +0200 (2006-02-19)
parents f1ba68510fed
children db51b62442ac
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_email;
72 sub lm_show_labs;
74 sub load_run;
75 sub save_run;
76 sub print_log;
77 sub print_usage_info;
78 sub main();
80 main();
82 sub main()
83 {
84 binmode STDOUT, ":utf8";
86 if (! @ARGV) {
87 print_usage_info();
88 exit(0);
89 }
91 init_config();
92 #load_config;
93 load_run;
94 load_scripts;
95 load_class;
96 load_course;
98 my $arg = join " ", @ARGV;
100 # Getting @SelectedMachines if any
101 if ($arg =~ s/@(.*?)\s//) {
102 my $machines = $1;
103 my @list = split /,/, $machines;
104 for my $interval (@list) {
105 my ($first, $last) = split /-/, $interval;
107 push @SelectedMachines, $first;
108 while ($first < $last) {
109 push @SelectedMachines, ++$first;
110 }
111 }
112 }
114 # Choose command to do
115 switch ($arg) {
116 case "next" { lm_next }
117 case "prev" { lm_prev }
118 case /set / { $arg =~ /set (.*)/; lm_set $1 }
119 case "report" { lm_report }
120 case "start" { lm_start }
121 case "stop" { lm_stop }
122 case "show hosts" { lm_show_hosts }
123 case "show email" { lm_show_email }
124 case "show labs" { lm_show_labs }
125 case /do / { $arg =~ /do (.*)/; lm_do "$1" }
126 else { print_usage_info() }
127 }
128 save_run;
129 exit(0);
130 }
132 sub load_scripts
133 {
134 open (SCRIPTS, "$Config{l3scripts}")
135 or die "Cant open l3scripts file: ".$Config{l3scripts}.": $!\n";
136 binmode SCRIPTS, ":utf8";
137 local $/;
138 $_=<SCRIPTS>;
139 close(SCRIPTS);
141 %Scripts = ("empty-element", split (/###(.*)\n/));
142 delete($Scripts{"empty-element"});
144 }
146 sub load_config
147 {
148 my %file_config;
149 my %argv_config;
150 #read_config_file(\%file_config, $Config_File);
151 GetOptions(\%argv_config, map "$_=s", keys %Config);
152 %Config = (%Config, %file_config, %argv_config);
153 }
155 sub load_course
156 {
157 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )
158 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
159 # print Dumper($XMLCourse);
160 for my $lab (@{$XMLCourse->{"module"}}) {
161 push @Labs, $lab->{"code"};
162 }
163 }
165 sub load_class
166 {
167 my $classfile =
168 $Config{"classfile"} ||
169 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
170 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )
171 or die "Can't open file of the class ",$classfile,"\n";
173 for my $student (@{$XMLClass->{"student"}}) {
174 $Machines{$student->{"host"}} = {
175 "name" => "$student->{firstname} $student->{surname}",
176 "firstname" => "$student->{firstname}",
177 "user" => "$student->{user}",
178 "email" => "$student->{email}",
179 "student" => $student,
180 }
181 }
182 # print Dumper($XMLClass);
183 # print Dumper(\%Machines);
184 }
187 sub lm_next
188 {
189 for(my $i=0; $i<=$#Labs; $i++){
190 if ( $Labs[$i] eq $Run{"lab"} ) {
191 if ($i < $#Labs) {
192 lm_set($Labs[$i+1]);
193 return ;
194 } else {
195 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
196 }
197 }
199 }
200 die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
201 }
203 sub lm_prev
204 # Switch to previous lab
205 {
206 for(my $i=0; $i<=$#Labs; $i++){
207 if ( $Labs[$i] eq $Run{"lab"} ) {
208 if ($i > 0) {
209 lm_set($Labs[$i-1]);
210 return ;
211 } else {
212 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
213 }
214 }
216 }
217 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
218 }
220 sub lm_set
221 # Switch to $_[0] lab
222 # FIXME
223 {
224 my $lab = shift;
225 print "Current lab is $lab\n";
226 $Run{"lab"} = "$lab";
227 lm_do "setlab", $lab;
228 }
231 sub lm_start
232 # Start new training day
233 {
234 print_log(`date`." STARTED\n");
235 if ($Run{"lab"}) {
236 lm_next;
237 }
238 else
239 {
240 # First lab in the course
241 lm_set($Labs[0]);
242 }
243 }
245 sub lm_stop
246 # Stop this training day
247 {
248 print_log(`date`." STOPPED\n");
249 }
252 sub lm_show_hosts
253 # Show hosts used to run a commands
254 {
255 my $i=1;
256 for my $m (sort keys %Machines) {
257 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
258 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
259 }
260 $i++;
261 }
262 }
264 sub lm_show_email
265 # Show hosts used to run a commands
266 {
267 my $i=1;
268 for my $m (sort keys %Machines) {
269 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
270 print $Machines{$m}->{"email"},"\t",$Machines{$m}->{"name"},"\n";
271 }
272 $i++;
273 }
274 }
276 sub lm_show_labs
277 # Show hosts used to run a commands
278 {
279 my $i=1;
280 for my $lab (@Labs) {
281 print $lab;
282 print "*" if $lab eq $Run{"lab"};
283 print "\n";
284 }
285 }
287 sub lm_do
288 # Do the $_[0] command on all of the hosts
289 {
290 my $command = shift;
291 my $arg = join " ", @_;
292 my $i=1;
294 my %myenv = ( %Config,
295 lab => $arg,
296 center => $XMLClass->{"center"},
297 course => $XMLClass->{"course"},
298 date => $XMLClass->{"date"},
299 stopdate => $XMLClass->{"stop-date"},
300 instructor => $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"},
301 manager => $XMLClass->{"manager"}->{"firstname"}." ".$XMLClass->{"manager"}->{"surname"},
302 coursepath => $XMLCourse->{"path"},
303 );
305 if (grep { $_ eq "PRE-$command"} keys %Scripts) {
306 $_=$Scripts{"PRE-$command"};
307 s/\$(\w+)/$myenv{$1}/ge;
308 open(SHELL, "|/bin/sh -s");
309 binmode SHELL, ":utf8";
310 print SHELL $_;
311 close (SHELL);
312 }
315 for my $m (sort keys %Machines) {
316 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
317 print "$m:\n" if $Config{"show_host"} =~ /y/i;
319 %myenv = ( %myenv,
320 host => $m,
321 ipaddress => $Machines{$m}->{"ipaddress"},
322 dirs => "/root /home/".$Machines{$m}->{"user"},
323 lablogs => $Config{"path_lablogs"}."/".
324 $XMLClass->{"course"}."/".
325 $XMLClass->{"date"}."/".
326 "$m",
327 email => $Machines{$m}->{"student"}->{"email"},
328 company => $Machines{$m}->{"student"}->{"company"},
329 name => $Machines{$m}->{"name"},
330 firstname => $Machines{$m}->{"firstname"},
331 );
332 if (grep { $_ eq $command} keys %Scripts) {
333 $_=$Scripts{"$command"};
334 s/\$(\w+)/$myenv{$1}/ge;
335 open(SHELL, "|/bin/sh -s");
336 binmode SHELL, ":utf8";
337 print SHELL $_;
338 close (SHELL);
339 }
340 else {
341 my $res = `ssh $Config{"ssh_user"}\@$m $command`;
342 if ($res) {
343 my $count = ($res =~ s/(^)/$m: /mg);
344 print $res;
345 print "\n" if ($count > 1);
346 }
347 }
348 }
349 $i++;
350 }
352 if (grep { $_ eq "POST-$command"} keys %Scripts) {
353 $_=$Scripts{"POST-$command"};
354 s/\$(\w+)/$myenv{$1}/ge;
355 open(SHELL, "|/bin/sh -s");
356 binmode SHELL, ":utf8";
357 print SHELL $_;
358 close (SHELL);
359 }
360 }
364 =cut comment
366 lm report
368 Построить html представление для журналов текущего класса.
369 Для построения используется скрипт l3-report.
371 =cut
373 sub lm_report
374 {
376 my $webdir = $Config{"path_web"};
377 my $course=$XMLClass->{"course"};
378 my $date=$XMLClass->{"date"};
379 my $encoding=$XMLClass->{"charset"};
381 my $center = $XMLClass->{"center"};
382 my $instructor = $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"};
383 my $course_name = $XMLCourse->{"fullname"}[0];
386 # Собственно журналы
388 for my $student (@{$XMLClass->{"student"}}) {
389 my $user = $student->{"user"};
390 my $hostname = $student->{"host"};
391 my $encoding = $student->{"charset"};
392 my $student_name = $student->{"firstname"}." ".$student->{"surname"};
394 system("mkdir -p $webdir/$date/$hostname");
395 system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname");
396 system($Config{"l3-report"}.
397 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user".
398 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ".
399 $Config{"path_lablogs"}."/$course/$date/$hostname/root".
400 " --output $webdir/$date/$hostname/$user.html".
401 " --course-name '$course_name'".
402 " --course-code '$course'".
403 " --course-date '$date'".
404 " --course-center '$center'".
405 " --course-student '$student_name'".
406 " --course-trainer '$instructor'".
407 " --encoding $encoding"
408 );
409 system($Config{"l3-report"}.
410 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root".
411 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ".
412 " --output $webdir/$date/$hostname/root.html".
413 " --course-name '$course_name'".
414 " --course-code '$course'".
415 " --course-date '$date'".
416 " --course-center '$center'".
417 " --course-student '$student_name'".
418 " --course-trainer '$instructor'".
419 " --encoding $encoding"
420 );
421 }
423 # Индекс для данного класса
425 my $head;
427 $head="Журналы лабораторных работ";
428 open(HTML, ">$webdir/$date/index.html")
429 or die "Can't open $webdir/$date/index.html for writing";
430 binmode HTML, ":utf8";
431 print HTML <<HEAD;
432 <html>
433 <head>
434 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
435 <title>$head</title>
436 </head>
437 <body>
438 <h1>$head</h1>
439 <p>
440 Курс: $course_name ($course)<br/>
441 Начало: $date<br/>
442 Учебный центр: $center <br/>
443 Инструктор: $instructor <br/>
444 </p>
445 <table>
446 HEAD
447 for my $student (@{$XMLClass->{"student"}}) {
448 my $user = $student->{"user"};
449 my $hostname = $student->{"host"};
450 print HTML "<tr>\n";
451 print HTML "<td>",$student->{"firstname"}," ",$student->{"surname"},"</td>\n";
452 print HTML "<td>",$hostname,"</td>\n";
453 print HTML "<td><a href=\"$hostname/$user.html\">",$user,"</td>\n";
454 print HTML "<td><a href=\"$hostname/root.html\">","root","</td>\n";
455 print HTML "</tr>\n";
456 }
457 print HTML <<TAIL;
458 </table>
459 </html>
460 TAIL
461 close (HTML);
465 }
467 sub load_run
468 {
469 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
470 open (RUN, $runfile)
471 or return;
472 while (<RUN>) {
473 chomp;
474 my ($var, $val) = split /\s+/,$_,2;
475 $Run{$var}=$val;
476 }
477 close (RUN);
478 }
480 sub save_run
481 {
482 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
483 open (RN, "$runfile")
484 or die "Can't save running state to $runfile";
485 for my $var (keys %Run) {
486 print RN $var,"\t",$Run{$var},"\n";
487 }
488 close (RN);
489 }
491 sub print_log
492 {
493 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
494 open (LOG, ">>$logfile")
495 or die "Can't open logfile $logfile for writing";
496 print LOG @_;
497 close (LOG);
498 }
501 sub print_usage_info
502 {
503 print "Usage:\n\n\t$0 [host-list] command\n";
504 print <<'USAGE';
506 Commands:
508 next -- next lab
509 prev -- prev lab
510 set LAB -- set current lab to LAB
511 start -- start this day training
512 stop -- stop this day training
513 show hosts -- show available hosts in the class
514 show labs -- show available labs in the course
515 do COMMAND -- do specified command on the hosts of hostlist
516 report -- generate XML/HTML reports
519 do commands:
521 install [PROFILE] -- install profile
523 Host list:
525 @N -- machine N
526 @N1-N2 -- all of the machines from N1 to N2
527 @N1,N2,N3 -- machine N1, N2 and N3
529 N* is numbers or domain names of the machines.
531 If host list is not specified,
532 command is executed on all of the machines
534 USAGE
535 }