lilalo
view lm @ 82:7fb205f2c514
Увеличено количество строк вывода при распознавании агентом
| author | devi | 
|---|---|
| date | Fri Feb 24 08:49:31 2006 +0200 (2006-02-24) | 
| 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 }
