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