devi@0: #!/usr/bin/perl devi@0: devi@0: devi@0: use strict; devi@0: use Data::Dumper; devi@0: use Switch; devi@0: use XML::Simple; devi@0: use Getopt::Long; devi@4: use utf8; devi@0: devi@40: use lib "/usr/local/bin"; devi@40: use l3config; devi@40: devi@0: our $XMLClass; devi@0: our $XMLCourse; devi@0: our @Labs; devi@0: devi@92: our %Machines; # Machines list from class.xml devi@92: our @SelectedMachines; # Machines list given as the command line argument devi@0: devi@0: our $Config_File = "labmaker.conf"; devi@40: our %Config_ = ( devi@92: "show_host" => "no", devi@0: devi@92: # Вспомогательные программы devi@92: #"l3-report" => "./lm-report", devi@92: "l3-report" => "./l3-report", devi@3: devi@92: # Каталоги devi@92: "path_lilalo" => "/var/lilalo/", devi@92: "path_classes" => "/var/lilalo/classes/", devi@92: "path_lablogs" => "/var/lilalo/lablogs/", devi@92: "courses_path" => "/var/lilalo/courses/", devi@92: "outpath" => "/var/lilalo/out/", devi@92: "path_web" => "/var/www/l3", # Путь к web-отчётам devi@92: "path_share" => "./share/", # Путь к web-отчётам devi@0: devi@92: # Файлы devi@92: "runfile" => "lm.run", devi@92: "logfile" => "lm.log", devi@0: devi@92: "class" => "class", # Имя файла класса devi@92: "class_suffix" => ".xml", # Cуффикс файла класса devi@92: "classfile" => "", devi@0: devi@92: "sshkey" => "$ENV{HOME}/.ssh/id_dsa.pub", devi@92: "lmssh" => "./lm-ssh", devi@92: "lminstall" => "./lm-install", devi@92: "ssh_user" => "root", devi@0: ); devi@0: devi@0: our %Run = ( devi@92: "lab" => "" devi@0: ); devi@0: devi@0: our %Scripts; devi@0: devi@0: sub load_class; devi@0: sub load_config; devi@0: sub load_course; devi@0: sub load_scripts; devi@0: devi@92: sub lm_get; devi@0: sub lm_next; devi@0: sub lm_prev; devi@0: sub lm_start; devi@0: sub lm_stop; devi@0: sub lm_set; devi@0: sub lm_do; devi@0: sub lm_report; devi@0: sub lm_show_hosts; devi@69: sub lm_show_email; devi@0: sub lm_show_labs; devi@0: devi@0: sub load_run; devi@0: sub save_run; devi@0: sub print_log; devi@0: sub print_usage_info; devi@0: sub main(); devi@0: devi@0: main(); devi@0: devi@0: sub main() devi@0: { devi@92: binmode STDOUT, ":utf8"; devi@0: devi@92: if (! @ARGV) { devi@92: print_usage_info(); devi@92: exit(0); devi@92: } devi@0: devi@92: if ($ARGV[0] eq "get") { devi@92: lm_get; devi@92: exit(0); devi@92: } devi@0: devi@92: init_config(); devi@92: #load_config; devi@92: load_run; devi@92: load_scripts; devi@92: load_class; devi@92: load_course; devi@92: devi@92: my $arg = join " ", @ARGV; devi@0: devi@92: # Getting @SelectedMachines if any devi@92: if ($arg =~ s/@(.*?)\s//) { devi@92: my $machines = $1; devi@92: my @list = split /,/, $machines; devi@92: for my $interval (@list) { devi@92: my ($first, $last) = split /-/, $interval; devi@0: devi@92: push @SelectedMachines, $first; devi@92: while ($first < $last) { devi@92: push @SelectedMachines, ++$first; devi@92: } devi@92: } devi@92: } devi@92: devi@92: # Choose command to do devi@92: switch ($arg) { devi@92: case "next" { lm_next } devi@92: case "prev" { lm_prev } devi@92: case /set / { $arg =~ /set (.*)/; lm_set $1 } devi@92: case "report" { lm_report } devi@92: case "start" { lm_start } devi@92: case "stop" { lm_stop } devi@92: case "show hosts" { lm_show_hosts } devi@92: case "show email" { lm_show_email } devi@92: case "show labs" { lm_show_labs } devi@92: case /do / { $arg =~ /do (.*)/; lm_do "$1" } devi@92: else { print_usage_info() } devi@92: } devi@92: save_run; devi@92: exit(0); devi@0: } devi@0: devi@0: sub load_scripts devi@0: { devi@92: open (SCRIPTS, "$Config{l3scripts}") devi@92: or die "Cant open l3scripts file: ".$Config{l3scripts}.": $!\n"; devi@92: binmode SCRIPTS, ":utf8"; devi@92: local $/; devi@92: $_=; devi@92: close(SCRIPTS); devi@40: devi@92: %Scripts = ("empty-element", split (/###(.*)\n/)); devi@92: delete($Scripts{"empty-element"}); devi@40: devi@0: } devi@0: devi@0: sub load_config devi@0: { devi@92: my %file_config; devi@92: my %argv_config; devi@92: #read_config_file(\%file_config, $Config_File); devi@92: GetOptions(\%argv_config, map "$_=s", keys %Config); devi@92: %Config = (%Config, %file_config, %argv_config); devi@0: } devi@0: devi@0: sub load_course devi@0: { devi@92: $XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 ) devi@92: or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n"; devi@92: # print Dumper($XMLCourse); devi@92: for my $lab (@{$XMLCourse->{"module"}}) { devi@92: push @Labs, $lab->{"code"}; devi@92: } devi@0: } devi@0: devi@0: sub load_class devi@0: { devi@92: my $classfile = devi@92: $Config{"classfile"} || devi@92: $Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"}; devi@92: $XMLClass = XMLin($classfile , ForceArray => [ 'student' ] ) devi@92: or die "Can't open file of the class ",$classfile,"\n"; devi@0: devi@92: for my $student (@{$XMLClass->{"student"}}) { devi@92: $Machines{$student->{"host"}} = { devi@92: "name" => "$student->{firstname} $student->{surname}", devi@92: "firstname" => "$student->{firstname}", devi@92: "user" => "$student->{user}", devi@92: "email" => "$student->{email}", devi@92: "student" => $student, devi@92: } devi@92: } devi@92: # print Dumper($XMLClass); devi@92: # print Dumper(\%Machines); devi@92: } devi@92: devi@92: sub lm_get devi@92: { devi@92: print "Getting class description file..."; devi@94: if (system("cd $Config{path_classes}; wget -r --no-directories xgu.ru/l3/classes/class.xml") ==0 ) devi@92: { devi@92: print "Ok\n"; devi@92: } devi@92: else { devi@92: die "Can't load class file\n" devi@92: } devi@0: } devi@0: devi@0: devi@0: sub lm_next devi@0: { devi@92: for(my $i=0; $i<=$#Labs; $i++){ devi@92: if ( $Labs[$i] eq $Run{"lab"} ) { devi@92: if ($i < $#Labs) { devi@92: lm_set($Labs[$i+1]); devi@92: return ; devi@92: } else { devi@92: die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible" devi@92: } devi@92: } devi@92: devi@92: } devi@92: die "Lab ", $Run{"lab"}, " not found. Don't know which is next" devi@0: } devi@0: devi@0: sub lm_prev devi@0: # Switch to previous lab devi@0: { devi@92: for(my $i=0; $i<=$#Labs; $i++){ devi@92: if ( $Labs[$i] eq $Run{"lab"} ) { devi@92: if ($i > 0) { devi@92: lm_set($Labs[$i-1]); devi@92: return ; devi@92: } else { devi@92: die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible" devi@92: } devi@92: } devi@92: devi@92: } devi@92: die "Lab ", $Run{"lab"}, " not found. Don't know which is previous" devi@0: } devi@0: devi@0: sub lm_set devi@0: # Switch to $_[0] lab devi@0: # FIXME devi@0: { devi@92: my $lab = shift; devi@92: print "Current lab is $lab\n"; devi@92: $Run{"lab"} = "$lab"; devi@92: lm_do "setlab", $lab; devi@0: } devi@0: devi@0: devi@0: sub lm_start devi@0: # Start new training day devi@0: { devi@92: print_log(`date`." STARTED\n"); devi@92: if ($Run{"lab"}) { devi@92: lm_next; devi@92: } devi@92: else devi@92: { devi@92: # First lab in the course devi@92: lm_set($Labs[0]); devi@92: } devi@0: } devi@0: devi@0: sub lm_stop devi@0: # Stop this training day devi@0: { devi@92: print_log(`date`." STOPPED\n"); devi@0: } devi@0: devi@0: devi@0: sub lm_show_hosts devi@0: # Show hosts used to run a commands devi@0: { devi@92: my $i=1; devi@92: for my $m (sort keys %Machines) { devi@92: if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) { devi@92: print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n"; devi@92: } devi@92: $i++; devi@92: } devi@0: } devi@0: devi@69: sub lm_show_email devi@69: # Show hosts used to run a commands devi@69: { devi@92: my $i=1; devi@92: for my $m (sort keys %Machines) { devi@92: if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) { devi@92: print $Machines{$m}->{"email"},"\t",$Machines{$m}->{"name"},"\n"; devi@92: } devi@92: $i++; devi@92: } devi@69: } devi@69: devi@0: sub lm_show_labs devi@0: # Show hosts used to run a commands devi@0: { devi@92: my $i=1; devi@92: for my $lab (@Labs) { devi@92: print $lab; devi@92: print "*" if $lab eq $Run{"lab"}; devi@92: print "\n"; devi@92: } devi@0: } devi@0: devi@0: sub lm_do devi@0: # Do the $_[0] command on all of the hosts devi@0: { devi@92: my $command = shift; devi@92: my $arg = join " ", @_; devi@92: my $i=1; devi@40: devi@92: my %myenv = ( %Config, devi@92: lab => $arg, devi@92: center => $XMLClass->{"center"}, devi@92: course => $XMLClass->{"course"}, devi@92: date => $XMLClass->{"date"}, devi@92: stopdate => $XMLClass->{"stop-date"}, devi@92: instructor => $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"}, devi@92: manager => $XMLClass->{"manager"}->{"firstname"}." ".$XMLClass->{"manager"}->{"surname"}, devi@92: coursepath => $XMLCourse->{"path"}, devi@92: ); devi@40: devi@92: if (grep { $_ eq "PRE-$command"} keys %Scripts) { devi@92: $_=$Scripts{"PRE-$command"}; devi@92: s/\$(\w+)/$myenv{$1}/ge; devi@92: open(SHELL, "|/bin/sh -s"); devi@92: binmode SHELL, ":utf8"; devi@92: print SHELL $_; devi@92: close (SHELL); devi@92: } devi@40: devi@40: devi@92: for my $m (sort keys %Machines) { devi@92: if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) { devi@92: print "$m:\n" if $Config{"show_host"} =~ /y/i; devi@0: devi@92: %myenv = ( %myenv, devi@92: host => $m, devi@92: ipaddress => $Machines{$m}->{"ipaddress"}, devi@92: dirs => "/root /home/".$Machines{$m}->{"user"}, devi@92: lablogs => $Config{"path_lablogs"}."/". devi@92: $XMLClass->{"course"}."/". devi@92: $XMLClass->{"date"}."/". devi@92: "$m", devi@92: email => $Machines{$m}->{"student"}->{"email"}, devi@92: company => $Machines{$m}->{"student"}->{"company"}, devi@92: name => $Machines{$m}->{"name"}, devi@92: firstname => $Machines{$m}->{"firstname"}, devi@92: ); devi@92: if (grep { $_ eq $command} keys %Scripts) { devi@92: $_=$Scripts{"$command"}; devi@92: s/\$(\w+)/$myenv{$1}/ge; devi@92: open(SHELL, "|/bin/sh -s"); devi@92: binmode SHELL, ":utf8"; devi@92: print SHELL $_; devi@92: close (SHELL); devi@92: } devi@92: else { devi@92: my $res = `ssh $Config{"ssh_user"}\@$m $command`; devi@92: if ($res) { devi@92: my $count = ($res =~ s/(^)/$m: /mg); devi@92: print $res; devi@92: print "\n" if ($count > 1); devi@92: } devi@92: } devi@92: } devi@92: $i++; devi@92: } devi@40: devi@92: if (grep { $_ eq "POST-$command"} keys %Scripts) { devi@92: $_=$Scripts{"POST-$command"}; devi@92: s/\$(\w+)/$myenv{$1}/ge; devi@92: open(SHELL, "|/bin/sh -s"); devi@92: binmode SHELL, ":utf8"; devi@92: print SHELL $_; devi@92: close (SHELL); devi@92: } devi@0: } devi@0: devi@0: devi@3: devi@3: =cut comment devi@3: devi@3: lm report devi@3: devi@3: Построить html представление для журналов текущего класса. devi@3: Для построения используется скрипт l3-report. devi@3: devi@3: =cut devi@3: devi@0: sub lm_report devi@0: { devi@0: devi@92: my $webdir = $Config{"path_web"}; devi@92: my $course=$XMLClass->{"course"}; devi@92: my $date=$XMLClass->{"date"}; devi@92: my $encoding=$XMLClass->{"charset"}; devi@0: devi@92: my $center = $XMLClass->{"center"}; devi@92: my $instructor = $XMLClass->{"instructor"}->{"firstname"}." ".$XMLClass->{"instructor"}->{"surname"}; devi@92: my $course_name = $XMLCourse->{"fullname"}[0]; devi@4: devi@5: devi@92: # Собственно журналы devi@5: devi@92: for my $student (@{$XMLClass->{"student"}}) { devi@92: my $user = $student->{"user"}; devi@92: my $hostname = $student->{"host"}; devi@92: my $encoding = $student->{"charset"}; devi@92: my $student_name = $student->{"firstname"}." ".$student->{"surname"}; devi@5: devi@92: system("mkdir -p $webdir/$date/$hostname"); devi@92: system("cp ".$Config{"path_share"}."/*.{ico,css} $webdir/$date/$hostname"); devi@92: system($Config{"l3-report"}. devi@92: " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user". devi@92: " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/$user ". devi@92: $Config{"path_lablogs"}."/$course/$date/$hostname/root". devi@92: " --output $webdir/$date/$hostname/$user.html". devi@92: " --course-name '$course_name'". devi@92: " --course-code '$course'". devi@92: " --course-date '$date'". devi@92: " --course-center '$center'". devi@92: " --course-student '$student_name'". devi@92: " --course-trainer '$instructor'". devi@92: " --encoding $encoding" devi@92: ); devi@92: system($Config{"l3-report"}. devi@92: " --input ".$Config{"path_lablogs"}."/$course/$date/$hostname/root". devi@92: " --diffs ".$Config{"path_lablogs"}."/$course/$date/$hostname/root ". devi@92: " --output $webdir/$date/$hostname/root.html". devi@92: " --course-name '$course_name'". devi@92: " --course-code '$course'". devi@92: " --course-date '$date'". devi@92: " --course-center '$center'". devi@92: " --course-student '$student_name'". devi@92: " --course-trainer '$instructor'". devi@92: " --encoding $encoding" devi@92: ); devi@92: } devi@5: devi@92: # Индекс для данного класса devi@4: devi@92: my $head; devi@4: devi@92: $head="Журналы лабораторных работ"; devi@92: open(HTML, ">$webdir/$date/index.html") devi@92: or die "Can't open $webdir/$date/index.html for writing"; devi@92: binmode HTML, ":utf8"; devi@92: print HTML < devi@92: devi@92: devi@92: $head devi@92: devi@92: devi@92:

$head

devi@92:

devi@92: Курс: $course_name ($course)
devi@92: Начало: $date
devi@92: Учебный центр: $center
devi@92: Инструктор: $instructor
devi@92:

devi@92: devi@4: HEAD devi@92: for my $student (@{$XMLClass->{"student"}}) { devi@92: my $user = $student->{"user"}; devi@92: my $hostname = $student->{"host"}; devi@92: print HTML "\n"; devi@92: print HTML "\n"; devi@92: print HTML "\n"; devi@92: print HTML "\n"; devi@92: print HTML "\n"; devi@92: print HTML "\n"; devi@92: } devi@92: print HTML < devi@92: devi@4: TAIL devi@92: close (HTML); devi@4: devi@92: devi@92: devi@0: } devi@0: devi@0: sub load_run devi@0: { devi@92: my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"}; devi@92: open (RUN, $runfile) devi@92: or return; devi@92: while () { devi@92: chomp; devi@92: my ($var, $val) = split /\s+/,$_,2; devi@92: $Run{$var}=$val; devi@92: } devi@92: close (RUN); devi@0: } devi@0: devi@0: sub save_run devi@0: { devi@92: my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"}; devi@92: open (RN, "$runfile") devi@92: or die "Can't save running state to $runfile"; devi@92: for my $var (keys %Run) { devi@92: print RN $var,"\t",$Run{$var},"\n"; devi@92: } devi@92: close (RN); devi@0: } devi@0: devi@0: sub print_log devi@0: { devi@92: my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"}; devi@92: open (LOG, ">>$logfile") devi@92: or die "Can't open logfile $logfile for writing"; devi@92: print LOG @_; devi@92: close (LOG); devi@0: } devi@0: devi@0: devi@0: sub print_usage_info devi@0: { devi@92: print "Usage:\n\n\t$0 [host-list] command\n"; devi@92: print <<'USAGE'; devi@0: devi@0: Commands: devi@0: devi@92: next -- next lab devi@92: prev -- prev lab devi@92: set LAB -- set current lab to LAB devi@92: start -- start this day training devi@92: stop -- stop this day training devi@92: show hosts -- show available hosts in the class devi@92: show labs -- show available labs in the course devi@92: do COMMAND -- do specified command on the hosts of hostlist devi@92: report -- generate XML/HTML reports devi@0: devi@92: devi@0: do commands: devi@92: devi@92: install [PROFILE] -- install profile devi@92: devi@92: Host list: devi@0: devi@92: @N -- machine N devi@92: @N1-N2 -- all of the machines from N1 to N2 devi@92: @N1,N2,N3 -- machine N1, N2 and N3 devi@0: devi@92: N* is numbers or domain names of the machines. devi@92: devi@92: If host list is not specified, devi@92: command is executed on all of the machines devi@0: devi@40: USAGE devi@40: } devi@0: devi@0:
",$student->{"firstname"}," ",$student->{"surname"},"",$hostname,"",$user,"","root","