lilalo

view lm @ 92:db51b62442ac

Написан прототип lm get
author devi
date Sat Apr 22 17:08:05 2006 +0300 (2006-04-22)
parents 1e1422588716
children 45196265d30e
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_get;
64 sub lm_next;
65 sub lm_prev;
66 sub lm_start;
67 sub lm_stop;
68 sub lm_set;
69 sub lm_do;
70 sub lm_report;
71 sub lm_show_hosts;
72 sub lm_show_email;
73 sub lm_show_labs;
75 sub load_run;
76 sub save_run;
77 sub print_log;
78 sub print_usage_info;
79 sub main();
81 main();
83 sub main()
84 {
85 binmode STDOUT, ":utf8";
87 if (! @ARGV) {
88 print_usage_info();
89 exit(0);
90 }
92 if ($ARGV[0] eq "get") {
93 print "argv= ".$ARGV[0]."ZLO\n";
94 lm_get;
95 exit(0);
96 }
98 init_config();
99 #load_config;
100 load_run;
101 load_scripts;
102 load_class;
103 load_course;
105 my $arg = join " ", @ARGV;
107 # Getting @SelectedMachines if any
108 if ($arg =~ s/@(.*?)\s//) {
109 my $machines = $1;
110 my @list = split /,/, $machines;
111 for my $interval (@list) {
112 my ($first, $last) = split /-/, $interval;
114 push @SelectedMachines, $first;
115 while ($first < $last) {
116 push @SelectedMachines, ++$first;
117 }
118 }
119 }
121 # Choose command to do
122 switch ($arg) {
123 case "next" { lm_next }
124 case "prev" { lm_prev }
125 case /set / { $arg =~ /set (.*)/; lm_set $1 }
126 case "report" { lm_report }
127 case "start" { lm_start }
128 case "stop" { lm_stop }
129 case "show hosts" { lm_show_hosts }
130 case "show email" { lm_show_email }
131 case "show labs" { lm_show_labs }
132 case /do / { $arg =~ /do (.*)/; lm_do "$1" }
133 else { print_usage_info() }
134 }
135 save_run;
136 exit(0);
137 }
139 sub load_scripts
140 {
141 open (SCRIPTS, "$Config{l3scripts}")
142 or die "Cant open l3scripts file: ".$Config{l3scripts}.": $!\n";
143 binmode SCRIPTS, ":utf8";
144 local $/;
145 $_=<SCRIPTS>;
146 close(SCRIPTS);
148 %Scripts = ("empty-element", split (/###(.*)\n/));
149 delete($Scripts{"empty-element"});
151 }
153 sub load_config
154 {
155 my %file_config;
156 my %argv_config;
157 #read_config_file(\%file_config, $Config_File);
158 GetOptions(\%argv_config, map "$_=s", keys %Config);
159 %Config = (%Config, %file_config, %argv_config);
160 }
162 sub load_course
163 {
164 $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )
165 or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
166 # print Dumper($XMLCourse);
167 for my $lab (@{$XMLCourse->{"module"}}) {
168 push @Labs, $lab->{"code"};
169 }
170 }
172 sub load_class
173 {
174 my $classfile =
175 $Config{"classfile"} ||
176 $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
177 $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )
178 or die "Can't open file of the class ",$classfile,"\n";
180 for my $student (@{$XMLClass->{"student"}}) {
181 $Machines{$student->{"host"}} = {
182 "name" => "$student->{firstname} $student->{surname}",
183 "firstname" => "$student->{firstname}",
184 "user" => "$student->{user}",
185 "email" => "$student->{email}",
186 "student" => $student,
187 }
188 }
189 # print Dumper($XMLClass);
190 # print Dumper(\%Machines);
191 }
193 sub lm_get
194 {
195 print "Getting class description file...";
196 if (system("cd $Config{path_classes}; wget -r xgu.ru/l3/classes/class.xml") ==0 )
197 {
198 print "Ok\n";
199 }
200 else {
201 die "Can't load class file\n"
202 }
203 }
206 sub lm_next
207 {
208 for(my $i=0; $i<=$#Labs; $i++){
209 if ( $Labs[$i] eq $Run{"lab"} ) {
210 if ($i < $#Labs) {
211 lm_set($Labs[$i+1]);
212 return ;
213 } else {
214 die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
215 }
216 }
218 }
219 die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
220 }
222 sub lm_prev
223 # Switch to previous lab
224 {
225 for(my $i=0; $i<=$#Labs; $i++){
226 if ( $Labs[$i] eq $Run{"lab"} ) {
227 if ($i > 0) {
228 lm_set($Labs[$i-1]);
229 return ;
230 } else {
231 die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
232 }
233 }
235 }
236 die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
237 }
239 sub lm_set
240 # Switch to $_[0] lab
241 # FIXME
242 {
243 my $lab = shift;
244 print "Current lab is $lab\n";
245 $Run{"lab"} = "$lab";
246 lm_do "setlab", $lab;
247 }
250 sub lm_start
251 # Start new training day
252 {
253 print_log(`date`." STARTED\n");
254 if ($Run{"lab"}) {
255 lm_next;
256 }
257 else
258 {
259 # First lab in the course
260 lm_set($Labs[0]);
261 }
262 }
264 sub lm_stop
265 # Stop this training day
266 {
267 print_log(`date`." STOPPED\n");
268 }
271 sub lm_show_hosts
272 # Show hosts used to run a commands
273 {
274 my $i=1;
275 for my $m (sort keys %Machines) {
276 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
277 print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
278 }
279 $i++;
280 }
281 }
283 sub lm_show_email
284 # Show hosts used to run a commands
285 {
286 my $i=1;
287 for my $m (sort keys %Machines) {
288 if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
289 print $Machines{$m}->{"email"},"\t",$Machines{$m}->{"name"},"\n";
290 }
291 $i++;
292 }
293 }
295 sub lm_show_labs
296 # Show hosts used to run a commands
297 {
298 my $i=1;
299 for my $lab (@Labs) {
300 print $lab;
301 print "*" if $lab eq $Run{"lab"};
302 print "\n";
303 }
304 }
306 sub lm_do
307 # Do the $_[0] command on all of the hosts
308 {
309 my $command = shift;
310 my $arg = join " ", @_;
311 my $i=1;
313 my %myenv = ( %Config,
314 lab => $arg,
315 center => $XMLClass->{"center"},
316 course => $XMLClass->{"course"},
317 date => $XMLClass->{"date"},
318 stopdate => $XMLClass->{"stop-date"},
319 instructor => $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"},
320 manager => $XMLClass->{"manager"}->{"firstname"}." ".$XMLClass->{"manager"}->{"surname"},
321 coursepath => $XMLCourse->{"path"},
322 );
324 if (grep { $_ eq "PRE-$command"} keys %Scripts) {
325 $_=$Scripts{"PRE-$command"};
326 s/\$(\w+)/$myenv{$1}/ge;
327 open(SHELL, "|/bin/sh -s");
328 binmode SHELL, ":utf8";
329 print SHELL $_;
330 close (SHELL);
331 }
334 for my $m (sort keys %Machines) {
335 if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
336 print "$m:\n" if $Config{"show_host"} =~ /y/i;
338 %myenv = ( %myenv,
339 host => $m,
340 ipaddress => $Machines{$m}->{"ipaddress"},
341 dirs => "/root /home/".$Machines{$m}->{"user"},
342 lablogs => $Config{"path_lablogs"}."/".
343 $XMLClass->{"course"}."/".
344 $XMLClass->{"date"}."/".
345 "$m",
346 email => $Machines{$m}->{"student"}->{"email"},
347 company => $Machines{$m}->{"student"}->{"company"},
348 name => $Machines{$m}->{"name"},
349 firstname => $Machines{$m}->{"firstname"},
350 );
351 if (grep { $_ eq $command} keys %Scripts) {
352 $_=$Scripts{"$command"};
353 s/\$(\w+)/$myenv{$1}/ge;
354 open(SHELL, "|/bin/sh -s");
355 binmode SHELL, ":utf8";
356 print SHELL $_;
357 close (SHELL);
358 }
359 else {
360 my $res = `ssh $Config{"ssh_user"}\@$m $command`;
361 if ($res) {
362 my $count = ($res =~ s/(^)/$m: /mg);
363 print $res;
364 print "\n" if ($count > 1);
365 }
366 }
367 }
368 $i++;
369 }
371 if (grep { $_ eq "POST-$command"} keys %Scripts) {
372 $_=$Scripts{"POST-$command"};
373 s/\$(\w+)/$myenv{$1}/ge;
374 open(SHELL, "|/bin/sh -s");
375 binmode SHELL, ":utf8";
376 print SHELL $_;
377 close (SHELL);
378 }
379 }
383 =cut comment
385 lm report
387 Построить html представление для журналов текущего класса.
388 Для построения используется скрипт l3-report.
390 =cut
392 sub lm_report
393 {
395 my $webdir = $Config{"path_web"};
396 my $course=$XMLClass->{"course"};
397 my $date=$XMLClass->{"date"};
398 my $encoding=$XMLClass->{"charset"};
400 my $center = $XMLClass->{"center"};
401 my $instructor = $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"};
402 my $course_name = $XMLCourse->{"fullname"}[0];
405 # Собственно журналы
407 for my $student (@{$XMLClass->{"student"}}) {
408 my $user = $student->{"user"};
409 my $hostname = $student->{"host"};
410 my $encoding = $student->{"charset"};
411 my $student_name = $student->{"firstname"}." ".$student->{"surname"};
413 system("mkdir -p $webdir/$date/$hostname");
414 system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname");
415 system($Config{"l3-report"}.
416 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user".
417 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ".
418 $Config{"path_lablogs"}."/$course/$date/$hostname/root".
419 " --output $webdir/$date/$hostname/$user.html".
420 " --course-name '$course_name'".
421 " --course-code '$course'".
422 " --course-date '$date'".
423 " --course-center '$center'".
424 " --course-student '$student_name'".
425 " --course-trainer '$instructor'".
426 " --encoding $encoding"
427 );
428 system($Config{"l3-report"}.
429 " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root".
430 " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ".
431 " --output $webdir/$date/$hostname/root.html".
432 " --course-name '$course_name'".
433 " --course-code '$course'".
434 " --course-date '$date'".
435 " --course-center '$center'".
436 " --course-student '$student_name'".
437 " --course-trainer '$instructor'".
438 " --encoding $encoding"
439 );
440 }
442 # Индекс для данного класса
444 my $head;
446 $head="Журналы лабораторных работ";
447 open(HTML, ">$webdir/$date/index.html")
448 or die "Can't open $webdir/$date/index.html for writing";
449 binmode HTML, ":utf8";
450 print HTML <<HEAD;
451 <html>
452 <head>
453 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
454 <title>$head</title>
455 </head>
456 <body>
457 <h1>$head</h1>
458 <p>
459 Курс: $course_name ($course)<br/>
460 Начало: $date<br/>
461 Учебный центр: $center <br/>
462 Инструктор: $instructor <br/>
463 </p>
464 <table>
465 HEAD
466 for my $student (@{$XMLClass->{"student"}}) {
467 my $user = $student->{"user"};
468 my $hostname = $student->{"host"};
469 print HTML "<tr>\n";
470 print HTML "<td>",$student->{"firstname"}," ",$student->{"surname"},"</td>\n";
471 print HTML "<td>",$hostname,"</td>\n";
472 print HTML "<td><a href=\"$hostname/$user.html\">",$user,"</td>\n";
473 print HTML "<td><a href=\"$hostname/root.html\">","root","</td>\n";
474 print HTML "</tr>\n";
475 }
476 print HTML <<TAIL;
477 </table>
478 </html>
479 TAIL
480 close (HTML);
484 }
486 sub load_run
487 {
488 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
489 open (RUN, $runfile)
490 or return;
491 while (<RUN>) {
492 chomp;
493 my ($var, $val) = split /\s+/,$_,2;
494 $Run{$var}=$val;
495 }
496 close (RUN);
497 }
499 sub save_run
500 {
501 my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
502 open (RN, "$runfile")
503 or die "Can't save running state to $runfile";
504 for my $var (keys %Run) {
505 print RN $var,"\t",$Run{$var},"\n";
506 }
507 close (RN);
508 }
510 sub print_log
511 {
512 my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
513 open (LOG, ">>$logfile")
514 or die "Can't open logfile $logfile for writing";
515 print LOG @_;
516 close (LOG);
517 }
520 sub print_usage_info
521 {
522 print "Usage:\n\n\t$0 [host-list] command\n";
523 print <<'USAGE';
525 Commands:
527 next -- next lab
528 prev -- prev lab
529 set LAB -- set current lab to LAB
530 start -- start this day training
531 stop -- stop this day training
532 show hosts -- show available hosts in the class
533 show labs -- show available labs in the course
534 do COMMAND -- do specified command on the hosts of hostlist
535 report -- generate XML/HTML reports
538 do commands:
540 install [PROFILE] -- install profile
542 Host list:
544 @N -- machine N
545 @N1-N2 -- all of the machines from N1 to N2
546 @N1,N2,N3 -- machine N1, N2 and N3
548 N* is numbers or domain names of the machines.
550 If host list is not specified,
551 command is executed on all of the machines
553 USAGE
554 }