lilalo
view lm @ 0:18b21f6918f0
Initial revision
| author | devi | 
|---|---|
| date | Sun May 22 16:29:55 2005 +0300 (2005-05-22) | 
| parents | |
| children | 6c1d2b9f45e7 | 
 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;
    11 our $XMLClass;
    12 our $XMLCourse;
    13 our @Labs;
    15 our %Machines;			# Machines list from class.xml
    16 our @SelectedMachines;		# Machines list given as the command line argument
    18 our $Config_File = "labmaker.conf";
    19 our %Config = (
    20 	"show_host" 	=> "no",
    22 	# Каталоги
    23 	"path_labmaker" => "/var/labmaker/",
    24 	"path_classes"	=> "/var/labmaker/classes/",
    25 	"lablogs_path"	=> "/var/labmaker/lablogs/",
    26 	"courses_path"	=> "/var/labmaker/courses/",
    27 	"outpath"	=> "/var/labmaker/out/",
    29 	# Файлы
    30 	"runfile"	=> "lm.run", 
    31 	"logfile"	=> "lm.log", 
    33 	"class" 	=> "class", 				# Имя файла класса
    34 	"class_suffix" 	=> ".xml", 				# Cуффикс файла класса
    36 	"sshkey"	=> "$ENV{HOME}/.ssh/id_dsa.pub",
    37 	"lmssh"		=> "./lm-ssh",
    38 	"lminstall"	=> "./lm-install",
    39 	"ssh_user"	=> "r",
    40 );
    42 our %Run = (
    43 	"lab" => ""
    44 );
    46 our %Scripts;
    48 sub load_class;
    49 sub load_config;
    50 sub load_course;
    51 sub load_scripts;
    53 sub lm_next;
    54 sub lm_prev;
    55 sub lm_start;
    56 sub lm_stop;
    57 sub lm_set;
    58 sub lm_do;
    59 sub lm_report;
    60 sub lm_show_hosts;
    61 sub lm_show_labs;
    63 sub load_run;
    64 sub save_run;
    65 sub print_log;
    66 sub print_usage_info;
    67 sub main();
    69 main();
    71 sub main()
    72 {
    73 	binmode STDOUT, ":utf8";
    75 	if (! @ARGV) {
    76 		print_usage_info();
    77 		exit(0);
    78 	}
    80 	load_config;
    81 	load_run;
    82 	load_scripts;
    83 	load_class;
    84 	load_course;
    86 	my $arg = join " ", @ARGV;
    88 	# Getting @SelectedMachines if any
    89 	if ($arg =~ s/@(.*?)\s//) {
    90 		my $machines = $1;
    91 		my @list = split /,/, $machines;
    92 		for my $interval (@list) {
    93 			my ($first, $last) = split /-/, $interval;
    95 			push @SelectedMachines, $first;
    96 			while ($first < $last) {
    97 				push @SelectedMachines, ++$first;
    98 			}	
    99 		}
   100 	}
   102 	# Choose command to do
   103 	switch ($arg) {
   104 		case "next"	{ lm_next }
   105 		case "prev"	{ lm_prev }
   106 		case /set /	{ $arg =~ /set (.*)/; lm_set $1 }
   107 		case "report"	{ lm_report }
   108 		case "start"	{ lm_start }
   109 		case "stop"	{ lm_stop }
   110 		case "show hosts" { lm_show_hosts }
   111 		case "show labs" { lm_show_labs }
   112 		case /do /  { $arg =~ /do (.*)/;  lm_do "$1" }
   113 		else 		{ print_usage_info() }
   114 	}
   115 	save_run;
   116 	exit(0);
   117 }
   119 sub load_scripts
   120 {
   121 	local $/;
   122 	$_=<SCRIPTS>;
   123 	%Scripts = ("empty-element", split (/###(.*)\n/));
   124 	delete($Scripts{"empty-element"});
   125 }
   127 sub load_config
   128 {
   129 	my %file_config;
   130 	my %argv_config;
   131 	#read_config_file(\%file_config, $Config_File);
   132 	GetOptions(\%argv_config, map "$_=s", keys %Config);
   133 	%Config = (%Config, %file_config, %argv_config);
   134 }
   136 sub load_course
   137 {
   138 	$XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )  
   139 		or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
   140 #	print Dumper($XMLCourse);
   141 	for my $lab (@{$XMLCourse->{"module"}}) {
   142 		push @Labs, $lab->{"code"};
   143 	}
   144 }
   146 sub load_class
   147 {
   148 	my $classfile =
   149 	$Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
   150 	$XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )  
   151 		or die "Can't open file of the class ",$classfile,"\n";
   153 	for my $student (@{$XMLClass->{"student"}}) {
   154 		$Machines{$student->{"host"}} = {
   155 			"name"	=> "$student->{firstname} $student->{surname}",
   156 			"user"	=> "$student->{user}",
   157 			"student" => $student,
   158 		}	
   159 	}
   160 #	print Dumper($XMLClass);
   161 #	print Dumper(\%Machines);
   162 }
   165 sub lm_next
   166 {
   167 	for(my $i=0; $i<=$#Labs; $i++){
   168 		if ( $Labs[$i] eq $Run{"lab"} ) {
   169 			if ($i < $#Labs) {
   170 				lm_set($Labs[$i+1]);
   171 				return ;
   172 			} else {
   173 				die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
   174 			}
   175 		}
   177 	}
   178 	die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
   179 }
   181 sub lm_prev
   182 # Switch to previous lab
   183 {
   184 	for(my $i=0; $i<=$#Labs; $i++){
   185 		if ( $Labs[$i] eq $Run{"lab"} ) {
   186 			if ($i > 0) {
   187 				lm_set($Labs[$i-1]);
   188 				return ;
   189 			} else {
   190 				die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
   191 			}
   192 		}
   194 	}
   195 	die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
   196 }
   198 sub lm_set
   199 # Switch to $_[0] lab
   200 # FIXME
   201 {
   202 	my $lab = shift;
   203 	print "Current lab is $lab\n";
   204 	$Run{"lab"} = "$lab";
   205 	lm_do "setlab", $lab;
   206 }
   209 sub lm_start
   210 # Start new training day
   211 {
   212 	print_log(`date`." STARTED\n");
   213 	if ($Run{"lab"}) {
   214 		lm_next;
   215 	}
   216 	else
   217 	{
   218 		# First lab in the course
   219 		lm_set($Labs[0]);
   220 	}
   221 }
   223 sub lm_stop
   224 # Stop this training day
   225 {
   226 	print_log(`date`." STOPPED\n");
   227 }
   230 sub lm_show_hosts
   231 # Show hosts used to run a commands
   232 {
   233 	my $i=1;
   234 	for my $m (sort keys %Machines) {
   235 		if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
   236 			print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
   237 		}	
   238 		$i++;
   239 	}
   240 }
   242 sub lm_show_labs
   243 # Show hosts used to run a commands
   244 {
   245 	my $i=1;
   246 	for my $lab (@Labs) {
   247 		print $lab;
   248 		print "*" if $lab eq $Run{"lab"};
   249 		print "\n";
   250 	}
   251 }
   253 sub lm_do
   254 # Do the $_[0] command on all of the hosts 
   255 {
   256 	my $command = shift;
   257 	my $arg = join " ", @_;
   258 	my $i=1;
   259 	for my $m (sort keys %Machines) {
   260 		if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
   261 			print "$m:\n" if $Config{"show_host"} =~ /y/i;
   263 			my %myenv = ( %Config, 
   264 				host 	=>	$m,
   265 				dirs	=>	"/root /home/".$Machines{$m}->{"user"},
   266 				lablogs =>	$Config{"lablogs_path"}."/".
   267 						$XMLClass->{"course"}."/".
   268 						$XMLClass->{"date"}."/".
   269 						"$m",
   270 				lab	=> 	$arg,			
   272 				email	=>	$Machines{$m}->{"student"}->{"email"},
   273 				company	=>	$Machines{$m}->{"student"}->{"company"},
   274 				center 	=>	$XMLClass->{"center"},
   275 				course 	=>	$XMLClass->{"course"},
   276 				date 	=>	$XMLClass->{"date"},
   277 				name	=> 	$Machines{$m}->{"name"},
   278 				coursepath =>	$XMLCourse->{"path"},
   280 			);
   281 			if (grep { $_ eq $command} keys %Scripts) {
   282 				$_=$Scripts{"$command"};
   283 				s/\$(\w+)/$myenv{$1}/ge;
   284 				open(SHELL, "|/bin/sh -s");
   285 				binmode SHELL, ":utf8";
   286 				print SHELL $_;
   287 				close (SHELL);
   288 			}
   289 			else {
   290 				my $res = `ssh $Config{"ssh_user"}\@$m $command`;
   291 				if ($res) {
   292 					my $count = ($res =~ s/(^)/$m: /mg);
   293 					print $res;
   294 					print "\n" if ($count > 1);
   295 				}
   296 			}	
   297 		}	
   298 		$i++;
   299 	}
   300 }
   303 sub lm_report
   304 {
   306 	print "Not implemented yet\n";
   307 	exit(1);
   309 =cut comment
   311 Дальше идут скрипты, код которых нужно реализовать здесь.
   312 Как минимум.
   314 =cut 
   316 	my $lm_script_make_report_web = <<'SCRIPT';
   318 #!/bin/sh
   320 ####cd /home/devi/lm
   321 ./lm do copy-lablogs
   322 ##./lm-report --input /home/murk/.labmaker --output /var/www/lm/murk.html
   323 ##exit
   325 COURSE=ug-h
   326 DATE=2005-04-25
   327 SUFF=".linux.nt"
   328 #MACHINES="m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15"
   329 #MACHINES="m1 m2 m3 m4 m5 m6 m7 f1 f2 f3 f4 f5"
   330 MACHINES="m01 m02 m03 m04 m05 m06 m07 m08"
   331 #MACHINES="m1"
   332 USERS="user root"
   333 WEBDIR=/var/www/lm
   335 for u in $USERS
   336 	do
   337 		for m in $MACHINES
   338 			do
   339 				e=utf-8
   340 				[ "${m##f}" = "$m" ] || e=koi8-r
   341 				#e=koi8-r
   342 				mkdir -p $WEBDIR/$DATE/$m
   343 				cp share/*.ico share/*.css $WEBDIR/$m
   344 				#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   345 				./lm-report\
   346 					--input	Lablogs/$COURSE/$DATE/$m$SUFF/$u/ \
   347 					--diffs "Lablogs/$COURSE/$DATE/$m$SUFF/$u/ Lablogs/$COURSE/$DATE/$m$SUFF/root/"\
   348 					--output /var/www/lm/$DATE/$m/$u.html \
   349 					--encoding $e
   350 			done
   351 	done
   354 SCRIPT
   356 	my $lm_script_make_report_all = <<'SCRIPT';
   358 #!/bin/sh
   359 WEBDIR=/var/www/lm
   361 find . -type d -maxdepth 5 -mindepth 5 |\
   362 	while read dir
   363 	do
   364 		subdir=${dir##Lablogs/}
   365 		e=utf-8
   366 		echo $dir | grep -qi bsd && e=koi8-r
   367 		echo $dir | grep -qi /f && e=koi8-r
   369 		mkdir -p $WEBDIR/${subdir%/*}
   370 		cp share/*.ico share/*.css $WEBDIR/${subdir%/*}
   371 		#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   372 		./lm-report\
   373 			--input $dir	 \
   374 			--diffs "${dir%/user}/root $dir"\
   375 			--output $WEBDIR/$subdir.html \
   376 			--encoding $e
   377 	done
   379 SCRIPT
   380 }
   382 sub load_run
   383 {
   384 	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   385 	open (RUN, $runfile)
   386 		or return;
   387 	while (<RUN>) {
   388 		chomp;
   389 		my ($var, $val) = split /\s+/,$_,2;
   390 		$Run{$var}=$val;
   391 	}
   392 	close (RUN);	
   393 }
   395 sub save_run
   396 {
   397 	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   398 	open (RN, "$runfile")
   399 		or die "Can't save running state to $runfile";
   400 	for my $var (keys %Run) {
   401 		print RN $var,"\t",$Run{$var},"\n";
   402 	}
   403 	close (RN);	
   404 }
   406 sub print_log
   407 {
   408 	my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
   409 	open (LOG, ">>$logfile")
   410 		or die "Can't open logfile $logfile for writing";
   411 	print LOG  @_;
   412 	close (LOG);	
   413 }
   416 sub print_usage_info
   417 {
   418 	print "Usage:\n\n\t$0 [host-list] command\n";
   419 	while (<USAGE>) {
   420 		print $_;
   421 	}
   422 }
   424 __USAGE__
   426 Commands:
   428 	next		-- next lab
   429 	prev		-- prev lab
   430 	set LAB		-- set current lab to LAB
   431 	start		-- start this day training
   432 	stop		-- stop this day training
   433 	show hosts	-- show available hosts in the class
   434 	show labs	-- show available labs in the course
   435 	do COMMAND	-- do specified command on the hosts of hostlist
   436 	report		-- generate XML/HTML reports
   439 do commands:
   441 	install [PROFILE] -- install profile 
   443 Host list:	
   445 	@N		-- machine N
   446 	@N1-N2		-- all of the machines from N1 to N2
   447 	@N1,N2,N3	-- machine N1, N2 and N3
   449 	N* is numbers or domain names of the machines.
   451 	If host list is not specified, 
   452 	command is executed on all of the machines
   456 __SCRIPTS__
   457 ###install
   458 cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
   460 ###install-lm
   461 cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
   463 ###copy-lablogs
   464 for i in $dirs
   465 do
   466 	mkdir -p $lablogs/${i##*/}
   467 	scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
   468 done
   470 ###setlab
   471 for i in $dirs
   472 do
   473 	echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
   474 done
   476 ###makeout
   477 common=$course-$date
   478 personal=$course-$date-$email
   479 mkdir -p $outpath/${common}/{Lablogs,Docs}
   480 mkdir -p $outpath/${personal}/{Course,Files}
   481 cd $outpath/${personal}
   482 ln -s ../${common}/Lablogs .
   483 ln -s ../${common}/Docs .
   484 cd ~-
   485 export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
   486 export UG_CENTER="$center"
   487 export UG_COURSE="$course"
   488 export UG_DATE="$date"
   489 export UG_STUDENT="$name"
   490 export UG_COMPANY="$company"
   491 cd $coursepath; make personal; cd ~-
   493 ###watch
   494 cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker
