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