lilalo

diff lm @ 1:ff93ad94d73b

LiLaLo -- Live Lab Log
(L3)

Система автоматического ведения журналов
и автоматизированного управления ходом
лабораторных работ.
author devi
date Sun May 22 16:29:55 2005 +0300 (2005-05-22)
parents
children 6c1d2b9f45e7
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/lm	Sun May 22 16:29:55 2005 +0300
     1.3 @@ -0,0 +1,494 @@
     1.4 +#!/usr/bin/perl
     1.5 +
     1.6 +
     1.7 +use strict;
     1.8 +use Inline::Files;
     1.9 +use Data::Dumper;
    1.10 +use Switch;
    1.11 +use XML::Simple;
    1.12 +use Getopt::Long;
    1.13 +
    1.14 +our $XMLClass;
    1.15 +our $XMLCourse;
    1.16 +our @Labs;
    1.17 +
    1.18 +our %Machines;			# Machines list from class.xml
    1.19 +our @SelectedMachines;		# Machines list given as the command line argument
    1.20 +
    1.21 +our $Config_File = "labmaker.conf";
    1.22 +our %Config = (
    1.23 +	"show_host" 	=> "no",
    1.24 +
    1.25 +	# Каталоги
    1.26 +	"path_labmaker" => "/var/labmaker/",
    1.27 +	"path_classes"	=> "/var/labmaker/classes/",
    1.28 +	"lablogs_path"	=> "/var/labmaker/lablogs/",
    1.29 +	"courses_path"	=> "/var/labmaker/courses/",
    1.30 +	"outpath"	=> "/var/labmaker/out/",
    1.31 +
    1.32 +	# Файлы
    1.33 +	"runfile"	=> "lm.run", 
    1.34 +	"logfile"	=> "lm.log", 
    1.35 +
    1.36 +	"class" 	=> "class", 				# Имя файла класса
    1.37 +	"class_suffix" 	=> ".xml", 				# Cуффикс файла класса
    1.38 +
    1.39 +	"sshkey"	=> "$ENV{HOME}/.ssh/id_dsa.pub",
    1.40 +	"lmssh"		=> "./lm-ssh",
    1.41 +	"lminstall"	=> "./lm-install",
    1.42 +	"ssh_user"	=> "r",
    1.43 +);
    1.44 +
    1.45 +our %Run = (
    1.46 +	"lab" => ""
    1.47 +);
    1.48 +
    1.49 +our %Scripts;
    1.50 +
    1.51 +sub load_class;
    1.52 +sub load_config;
    1.53 +sub load_course;
    1.54 +sub load_scripts;
    1.55 +
    1.56 +sub lm_next;
    1.57 +sub lm_prev;
    1.58 +sub lm_start;
    1.59 +sub lm_stop;
    1.60 +sub lm_set;
    1.61 +sub lm_do;
    1.62 +sub lm_report;
    1.63 +sub lm_show_hosts;
    1.64 +sub lm_show_labs;
    1.65 +
    1.66 +sub load_run;
    1.67 +sub save_run;
    1.68 +sub print_log;
    1.69 +sub print_usage_info;
    1.70 +sub main();
    1.71 +
    1.72 +main();
    1.73 +
    1.74 +sub main()
    1.75 +{
    1.76 +	binmode STDOUT, ":utf8";
    1.77 +
    1.78 +	if (! @ARGV) {
    1.79 +		print_usage_info();
    1.80 +		exit(0);
    1.81 +	}
    1.82 +
    1.83 +	load_config;
    1.84 +	load_run;
    1.85 +	load_scripts;
    1.86 +	load_class;
    1.87 +	load_course;
    1.88 +	
    1.89 +	my $arg = join " ", @ARGV;
    1.90 +
    1.91 +	# Getting @SelectedMachines if any
    1.92 +	if ($arg =~ s/@(.*?)\s//) {
    1.93 +		my $machines = $1;
    1.94 +		my @list = split /,/, $machines;
    1.95 +		for my $interval (@list) {
    1.96 +			my ($first, $last) = split /-/, $interval;
    1.97 +
    1.98 +			push @SelectedMachines, $first;
    1.99 +			while ($first < $last) {
   1.100 +				push @SelectedMachines, ++$first;
   1.101 +			}	
   1.102 +		}
   1.103 +	}
   1.104 +
   1.105 +	# Choose command to do
   1.106 +	switch ($arg) {
   1.107 +		case "next"	{ lm_next }
   1.108 +		case "prev"	{ lm_prev }
   1.109 +		case /set /	{ $arg =~ /set (.*)/; lm_set $1 }
   1.110 +		case "report"	{ lm_report }
   1.111 +		case "start"	{ lm_start }
   1.112 +		case "stop"	{ lm_stop }
   1.113 +		case "show hosts" { lm_show_hosts }
   1.114 +		case "show labs" { lm_show_labs }
   1.115 +		case /do /  { $arg =~ /do (.*)/;  lm_do "$1" }
   1.116 +		else 		{ print_usage_info() }
   1.117 +	}
   1.118 +	save_run;
   1.119 +	exit(0);
   1.120 +}
   1.121 +
   1.122 +sub load_scripts
   1.123 +{
   1.124 +	local $/;
   1.125 +	$_=<SCRIPTS>;
   1.126 +	%Scripts = ("empty-element", split (/###(.*)\n/));
   1.127 +	delete($Scripts{"empty-element"});
   1.128 +}
   1.129 +
   1.130 +sub load_config
   1.131 +{
   1.132 +	my %file_config;
   1.133 +	my %argv_config;
   1.134 +	#read_config_file(\%file_config, $Config_File);
   1.135 +	GetOptions(\%argv_config, map "$_=s", keys %Config);
   1.136 +	%Config = (%Config, %file_config, %argv_config);
   1.137 +}
   1.138 +
   1.139 +sub load_course
   1.140 +{
   1.141 +	$XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )  
   1.142 +		or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
   1.143 +#	print Dumper($XMLCourse);
   1.144 +	for my $lab (@{$XMLCourse->{"module"}}) {
   1.145 +		push @Labs, $lab->{"code"};
   1.146 +	}
   1.147 +}
   1.148 +
   1.149 +sub load_class
   1.150 +{
   1.151 +	my $classfile =
   1.152 +	$Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
   1.153 +	$XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )  
   1.154 +		or die "Can't open file of the class ",$classfile,"\n";
   1.155 +
   1.156 +	for my $student (@{$XMLClass->{"student"}}) {
   1.157 +		$Machines{$student->{"host"}} = {
   1.158 +			"name"	=> "$student->{firstname} $student->{surname}",
   1.159 +			"user"	=> "$student->{user}",
   1.160 +			"student" => $student,
   1.161 +		}	
   1.162 +	}
   1.163 +#	print Dumper($XMLClass);
   1.164 +#	print Dumper(\%Machines);
   1.165 +}
   1.166 +
   1.167 +
   1.168 +sub lm_next
   1.169 +{
   1.170 +	for(my $i=0; $i<=$#Labs; $i++){
   1.171 +		if ( $Labs[$i] eq $Run{"lab"} ) {
   1.172 +			if ($i < $#Labs) {
   1.173 +				lm_set($Labs[$i+1]);
   1.174 +				return ;
   1.175 +			} else {
   1.176 +				die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
   1.177 +			}
   1.178 +		}
   1.179 +		
   1.180 +	}
   1.181 +	die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
   1.182 +}
   1.183 +
   1.184 +sub lm_prev
   1.185 +# Switch to previous lab
   1.186 +{
   1.187 +	for(my $i=0; $i<=$#Labs; $i++){
   1.188 +		if ( $Labs[$i] eq $Run{"lab"} ) {
   1.189 +			if ($i > 0) {
   1.190 +				lm_set($Labs[$i-1]);
   1.191 +				return ;
   1.192 +			} else {
   1.193 +				die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
   1.194 +			}
   1.195 +		}
   1.196 +		
   1.197 +	}
   1.198 +	die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
   1.199 +}
   1.200 +
   1.201 +sub lm_set
   1.202 +# Switch to $_[0] lab
   1.203 +# FIXME
   1.204 +{
   1.205 +	my $lab = shift;
   1.206 +	print "Current lab is $lab\n";
   1.207 +	$Run{"lab"} = "$lab";
   1.208 +	lm_do "setlab", $lab;
   1.209 +}
   1.210 +
   1.211 +
   1.212 +sub lm_start
   1.213 +# Start new training day
   1.214 +{
   1.215 +	print_log(`date`." STARTED\n");
   1.216 +	if ($Run{"lab"}) {
   1.217 +		lm_next;
   1.218 +	}
   1.219 +	else
   1.220 +	{
   1.221 +		# First lab in the course
   1.222 +		lm_set($Labs[0]);
   1.223 +	}
   1.224 +}
   1.225 +
   1.226 +sub lm_stop
   1.227 +# Stop this training day
   1.228 +{
   1.229 +	print_log(`date`." STOPPED\n");
   1.230 +}
   1.231 +
   1.232 +
   1.233 +sub lm_show_hosts
   1.234 +# Show hosts used to run a commands
   1.235 +{
   1.236 +	my $i=1;
   1.237 +	for my $m (sort keys %Machines) {
   1.238 +		if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
   1.239 +			print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
   1.240 +		}	
   1.241 +		$i++;
   1.242 +	}
   1.243 +}
   1.244 +
   1.245 +sub lm_show_labs
   1.246 +# Show hosts used to run a commands
   1.247 +{
   1.248 +	my $i=1;
   1.249 +	for my $lab (@Labs) {
   1.250 +		print $lab;
   1.251 +		print "*" if $lab eq $Run{"lab"};
   1.252 +		print "\n";
   1.253 +	}
   1.254 +}
   1.255 +
   1.256 +sub lm_do
   1.257 +# Do the $_[0] command on all of the hosts 
   1.258 +{
   1.259 +	my $command = shift;
   1.260 +	my $arg = join " ", @_;
   1.261 +	my $i=1;
   1.262 +	for my $m (sort keys %Machines) {
   1.263 +		if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
   1.264 +			print "$m:\n" if $Config{"show_host"} =~ /y/i;
   1.265 +
   1.266 +			my %myenv = ( %Config, 
   1.267 +				host 	=>	$m,
   1.268 +				dirs	=>	"/root /home/".$Machines{$m}->{"user"},
   1.269 +				lablogs =>	$Config{"lablogs_path"}."/".
   1.270 +						$XMLClass->{"course"}."/".
   1.271 +						$XMLClass->{"date"}."/".
   1.272 +						"$m",
   1.273 +				lab	=> 	$arg,			
   1.274 +				
   1.275 +				email	=>	$Machines{$m}->{"student"}->{"email"},
   1.276 +				company	=>	$Machines{$m}->{"student"}->{"company"},
   1.277 +				center 	=>	$XMLClass->{"center"},
   1.278 +				course 	=>	$XMLClass->{"course"},
   1.279 +				date 	=>	$XMLClass->{"date"},
   1.280 +				name	=> 	$Machines{$m}->{"name"},
   1.281 +				coursepath =>	$XMLCourse->{"path"},
   1.282 +
   1.283 +			);
   1.284 +			if (grep { $_ eq $command} keys %Scripts) {
   1.285 +				$_=$Scripts{"$command"};
   1.286 +				s/\$(\w+)/$myenv{$1}/ge;
   1.287 +				open(SHELL, "|/bin/sh -s");
   1.288 +				binmode SHELL, ":utf8";
   1.289 +				print SHELL $_;
   1.290 +				close (SHELL);
   1.291 +			}
   1.292 +			else {
   1.293 +				my $res = `ssh $Config{"ssh_user"}\@$m $command`;
   1.294 +				if ($res) {
   1.295 +					my $count = ($res =~ s/(^)/$m: /mg);
   1.296 +					print $res;
   1.297 +					print "\n" if ($count > 1);
   1.298 +				}
   1.299 +			}	
   1.300 +		}	
   1.301 +		$i++;
   1.302 +	}
   1.303 +}
   1.304 +
   1.305 +
   1.306 +sub lm_report
   1.307 +{
   1.308 +
   1.309 +	print "Not implemented yet\n";
   1.310 +	exit(1);
   1.311 +
   1.312 +=cut comment
   1.313 +
   1.314 +Дальше идут скрипты, код которых нужно реализовать здесь.
   1.315 +Как минимум.
   1.316 +
   1.317 +=cut 
   1.318 +
   1.319 +	my $lm_script_make_report_web = <<'SCRIPT';
   1.320 +
   1.321 +#!/bin/sh
   1.322 +
   1.323 +####cd /home/devi/lm
   1.324 +./lm do copy-lablogs
   1.325 +##./lm-report --input /home/murk/.labmaker --output /var/www/lm/murk.html
   1.326 +##exit
   1.327 +
   1.328 +COURSE=ug-h
   1.329 +DATE=2005-04-25
   1.330 +SUFF=".linux.nt"
   1.331 +#MACHINES="m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15"
   1.332 +#MACHINES="m1 m2 m3 m4 m5 m6 m7 f1 f2 f3 f4 f5"
   1.333 +MACHINES="m01 m02 m03 m04 m05 m06 m07 m08"
   1.334 +#MACHINES="m1"
   1.335 +USERS="user root"
   1.336 +WEBDIR=/var/www/lm
   1.337 +
   1.338 +for u in $USERS
   1.339 +	do
   1.340 +		for m in $MACHINES
   1.341 +			do
   1.342 +				e=utf-8
   1.343 +				[ "${m##f}" = "$m" ] || e=koi8-r
   1.344 +				#e=koi8-r
   1.345 +				mkdir -p $WEBDIR/$DATE/$m
   1.346 +				cp share/*.ico share/*.css $WEBDIR/$m
   1.347 +				#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   1.348 +				./lm-report\
   1.349 +					--input	Lablogs/$COURSE/$DATE/$m$SUFF/$u/ \
   1.350 +					--diffs "Lablogs/$COURSE/$DATE/$m$SUFF/$u/ Lablogs/$COURSE/$DATE/$m$SUFF/root/"\
   1.351 +					--output /var/www/lm/$DATE/$m/$u.html \
   1.352 +					--encoding $e
   1.353 +			done
   1.354 +	done
   1.355 +					
   1.356 +
   1.357 +SCRIPT
   1.358 +
   1.359 +	my $lm_script_make_report_all = <<'SCRIPT';
   1.360 +
   1.361 +#!/bin/sh
   1.362 +WEBDIR=/var/www/lm
   1.363 +
   1.364 +find . -type d -maxdepth 5 -mindepth 5 |\
   1.365 +	while read dir
   1.366 +	do
   1.367 +		subdir=${dir##Lablogs/}
   1.368 +		e=utf-8
   1.369 +		echo $dir | grep -qi bsd && e=koi8-r
   1.370 +		echo $dir | grep -qi /f && e=koi8-r
   1.371 +
   1.372 +		mkdir -p $WEBDIR/${subdir%/*}
   1.373 +		cp share/*.ico share/*.css $WEBDIR/${subdir%/*}
   1.374 +		#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   1.375 +		./lm-report\
   1.376 +			--input $dir	 \
   1.377 +			--diffs "${dir%/user}/root $dir"\
   1.378 +			--output $WEBDIR/$subdir.html \
   1.379 +			--encoding $e
   1.380 +	done
   1.381 +
   1.382 +SCRIPT
   1.383 +}
   1.384 +
   1.385 +sub load_run
   1.386 +{
   1.387 +	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   1.388 +	open (RUN, $runfile)
   1.389 +		or return;
   1.390 +	while (<RUN>) {
   1.391 +		chomp;
   1.392 +		my ($var, $val) = split /\s+/,$_,2;
   1.393 +		$Run{$var}=$val;
   1.394 +	}
   1.395 +	close (RUN);	
   1.396 +}
   1.397 +
   1.398 +sub save_run
   1.399 +{
   1.400 +	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   1.401 +	open (RN, "$runfile")
   1.402 +		or die "Can't save running state to $runfile";
   1.403 +	for my $var (keys %Run) {
   1.404 +		print RN $var,"\t",$Run{$var},"\n";
   1.405 +	}
   1.406 +	close (RN);	
   1.407 +}
   1.408 +
   1.409 +sub print_log
   1.410 +{
   1.411 +	my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
   1.412 +	open (LOG, ">>$logfile")
   1.413 +		or die "Can't open logfile $logfile for writing";
   1.414 +	print LOG  @_;
   1.415 +	close (LOG);	
   1.416 +}
   1.417 +
   1.418 +
   1.419 +sub print_usage_info
   1.420 +{
   1.421 +	print "Usage:\n\n\t$0 [host-list] command\n";
   1.422 +	while (<USAGE>) {
   1.423 +		print $_;
   1.424 +	}
   1.425 +}
   1.426 +
   1.427 +__USAGE__
   1.428 +
   1.429 +Commands:
   1.430 +
   1.431 +	next		-- next lab
   1.432 +	prev		-- prev lab
   1.433 +	set LAB		-- set current lab to LAB
   1.434 +	start		-- start this day training
   1.435 +	stop		-- stop this day training
   1.436 +	show hosts	-- show available hosts in the class
   1.437 +	show labs	-- show available labs in the course
   1.438 +	do COMMAND	-- do specified command on the hosts of hostlist
   1.439 +	report		-- generate XML/HTML reports
   1.440 +
   1.441 +	
   1.442 +do commands:
   1.443 +	
   1.444 +	install [PROFILE] -- install profile 
   1.445 +	
   1.446 +Host list:	
   1.447 +
   1.448 +	@N		-- machine N
   1.449 +	@N1-N2		-- all of the machines from N1 to N2
   1.450 +	@N1,N2,N3	-- machine N1, N2 and N3
   1.451 +
   1.452 +	N* is numbers or domain names of the machines.
   1.453 +	
   1.454 +	If host list is not specified, 
   1.455 +	command is executed on all of the machines
   1.456 +
   1.457 +
   1.458 +
   1.459 +__SCRIPTS__
   1.460 +###install
   1.461 +cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
   1.462 +
   1.463 +###install-lm
   1.464 +cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
   1.465 +
   1.466 +###copy-lablogs
   1.467 +for i in $dirs
   1.468 +do
   1.469 +	mkdir -p $lablogs/${i##*/}
   1.470 +	scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
   1.471 +done
   1.472 +
   1.473 +###setlab
   1.474 +for i in $dirs
   1.475 +do
   1.476 +	echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
   1.477 +done
   1.478 +
   1.479 +###makeout
   1.480 +common=$course-$date
   1.481 +personal=$course-$date-$email
   1.482 +mkdir -p $outpath/${common}/{Lablogs,Docs}
   1.483 +mkdir -p $outpath/${personal}/{Course,Files}
   1.484 +cd $outpath/${personal}
   1.485 +ln -s ../${common}/Lablogs .
   1.486 +ln -s ../${common}/Docs .
   1.487 +cd ~-
   1.488 +export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
   1.489 +export UG_CENTER="$center"
   1.490 +export UG_COURSE="$course"
   1.491 +export UG_DATE="$date"
   1.492 +export UG_STUDENT="$name"
   1.493 +export UG_COMPANY="$company"
   1.494 +cd $coursepath; make personal; cd ~-
   1.495 +
   1.496 +###watch
   1.497 +cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker