You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vcl.apache.org by ar...@apache.org on 2010/10/13 18:58:54 UTC

svn commit: r1022187 - in /incubator/vcl/trunk/managementnode/lib/VCL/Module/OS: Windows.pm Windows/Version_5.pm

Author: arkurth
Date: Wed Oct 13 16:58:52 2010
New Revision: 1022187

URL: http://svn.apache.org/viewvc?rev=1022187&view=rev
Log:
VCL-390
Updated Windows.pm::get_network_configuration to call utils.pm::is_public_ip_address().  This code was duplicated in the Windows.pm subroutine and was missing some additional logic included in utils.pm.  Previously, the Windows subroutine considered 169.254 addresses public and would return the first one it found if the public information was requested.  This caused the wrong information to be returned if another interface with a valid public address exists.

VCL-391
Updated places where tsshutdn.exe or shutdown.exe is called to only call tsshutdn.exe if Windows Server 2003 is used.  I've seen this hang on Windows XP.

Other
Added Windows.pm::clear_event_log.  This is called before a computer is shutdown if Sysprep is not used.  This causes only the events that happen during and after an image is loaded to appear in the Event Viewer, making it easier to determine the events related to that image being loaded and also removing older security events which the reservation user shouldn't see.

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_5.pm

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1022187&r1=1022186&r2=1022187&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Wed Oct 13 16:58:52 2010
@@ -3124,7 +3124,8 @@ sub reboot {
 		# Check if tsshutdn.exe exists on the computer
 		# tsshutdn.exe is the preferred utility, shutdown.exe often fails on Windows Server 2003
 		my $reboot_command;
-		if ($self->file_exists("$system32_path/tsshutdn.exe")) {
+		my $windows_product_name = $self->get_product_name() || '';
+		if ($windows_product_name =~ /2003/ && $self->file_exists("$system32_path/tsshutdn.exe")) {
 			$reboot_command = "$system32_path/tsshutdn.exe 0 /REBOOT /DELAY:0 /V";
 		}
 		else {
@@ -3272,6 +3273,9 @@ sub shutdown {
 	# Kill the screen saver process, it occasionally prevents reboots and shutdowns from working
 	$self->kill_process('logon.scr');
 	
+	# Clear the event log before shutting down
+	$self->clear_event_log();
+	
 	my $shutdown_command = "/bin/cygstart.exe cmd.exe /c \"";
 	
 	if ($disable_dhcp) {
@@ -3296,8 +3300,9 @@ sub shutdown {
 	}
 	
 	# Check if tsshutdn.exe exists on the computer
-	# tsshutdn.exe is the preferred utility, shutdown.exe often fails on Windows Server 2003
-	if ($self->file_exists("$system32_path/tsshutdn.exe")) {
+	# tsshutdn.exe is the preferred utility for Windows 2003, shutdown.exe often fails
+	my $windows_product_name = $self->get_product_name() || '';
+	if ($windows_product_name =~ /2003/ && $self->file_exists("$system32_path/tsshutdn.exe")) {
 		$shutdown_command .= "$system32_path/tsshutdn.exe 0 /POWERDOWN /DELAY:0 /V";
 	}
 	else {
@@ -4897,7 +4902,7 @@ sub get_network_configuration {
 		}
 		
 		# Check if interface has private IP address assigned to it
-		if (grep(/$computer_private_ip_address/, @ip_addresses)) {
+		if (grep { $_ eq $computer_private_ip_address } @ip_addresses) {
 			# If private interface information was requested, return a hash containing only this interface
 			notify($ERRORS{'DEBUG'}, 0, "private interface found: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
 			if ($network_type =~ /private/i) {
@@ -4911,42 +4916,19 @@ sub get_network_configuration {
 		}
 		
 		# Check if the interface should be ignored based on the name or description
-		if ($interface_name =~ /loopback|vmnet|afs|tunnel|6to4|isatap|teredo/i) {
-			notify($ERRORS{'DEBUG'}, 0, "interface ignored because of name: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
+		if ($interface_name =~ /(loopback|vmnet|afs|tunnel|6to4|isatap|teredo)/i) {
+			notify($ERRORS{'DEBUG'}, 0, "interface '$interface_name' ignored because name contains '$1', address(es): " . join (", ", @ip_addresses));
 			next;
 		}
-		elsif ($description =~ /loopback|virtual|afs|tunnel|pseudo|6to4|isatap/i) {
-			notify($ERRORS{'DEBUG'}, 0, "interface ignored because of description: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
+		elsif ($description =~ /(loopback|virtual|afs|tunnel|pseudo|6to4|isatap)/i) {
+			notify($ERRORS{'DEBUG'}, 0, "interface '$interface_name' ignored because description contains '$1': '$description', address(es): " . join (", ", @ip_addresses));
 			next;
 		}
 		
 		# Loop through the IP addresses for the interface
 		# Once a public address is found, return the data for that interface
 		for my $ip_address (@ip_addresses) {
-			# Split up the IP address being checked into its octets
-			my @octets = split(/\./, $ip_address);
-			
-			# Determine if this is a private or public address
-			# Private:
-			#   10.0.0.0    - 10.255.255.255
-			#   172.16.0.0  - 172.16.31.255.255
-			#   192.168.0.0 - 192.168.255.255
-			if (($octets[0] == 10) ||
-				 ($octets[0] != 172 && ($octets[1] >= 16 && $octets[1] <= 31)) ||
-				 ($octets[0] == 192 && $octets[1] == 168)
-				) {
-				notify($ERRORS{'DEBUG'}, 0, "interface found with private address not matching private address for reservation: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
-				
-				if (keys(%public_interface)) {
-					notify($ERRORS{'DEBUG'}, 0, "already found another interface with a private address not matching private address for reservation, this one will be used if a public address isn't found");
-					next;
-				}
-				else {
-					notify($ERRORS{'DEBUG'}, 0, "interface will be returned if another with a public address isn't found");
-					$public_interface{$interface_name} = $network_configuration{$interface_name};
-				}
-			}
-			else {
+			if (is_public_ip_address($ip_address)) {
 				notify($ERRORS{'DEBUG'}, 0, "public interface found: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
 				if ($network_type =~ /public/i) {
 					my %return_hash = ($interface_name => $network_configuration{$interface_name});
@@ -4957,6 +4939,19 @@ sub get_network_configuration {
 					next;
 				}
 			}
+			else {
+				notify($ERRORS{'DEBUG'}, 0, "interface found with non-public address not matching private address for reservation: $interface_name, description: $description, address(es): " . join (", ", @ip_addresses));
+				
+				if (keys(%public_interface)) {
+					notify($ERRORS{'DEBUG'}, 0, "already found another interface with a non-public address not matching private address for reservation, this one will be used if a public address isn't found");
+					next;
+				}
+				else {
+					notify($ERRORS{'DEBUG'}, 0, "interface will be returned if another with a public address isn't found");
+					$public_interface{$interface_name} = $network_configuration{$interface_name};
+				}
+			}
+			
 		}
 	}
 
@@ -9726,6 +9721,64 @@ sub sanitize_files {
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 clear_event_log
+
+ Parameters  : @logfile_names (optional)
+ Returns     : boolean
+ Description : Clears the Windows 'Application', 'Security', 'System' event
+               logs. One or more event logfile names may be specified to only
+               clear certain event logs.
+
+=cut
+
+sub clear_event_log {
+	my $self = shift;
+	unless (ref($self) && $self->isa('VCL::Module')) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+	
+	my @logfile_names = @_;
+	@logfile_names = ('Application', 'Security', 'System') if !@logfile_names;
+	
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+	my $system32_path        = $self->get_system32_path() || return;
+	
+	# Assemble the command
+	# Call wmic.exe - the WMI shell
+	# wmic.exe will hang if it is called by itself.  It has something to do with TTY/PTY
+	# Piping the echo command seems to prevent it from hanging
+	my $command;
+	for my $logfile_name (@logfile_names) {
+		$command .= "echo | $system32_path/Wbem/wmic.exe NTEVENTLOG WHERE LogFileName=\\\"$logfile_name\\\" CALL ClearEventLog ; ";
+	}
+	
+	# Remove the last ' ; ' added to the command
+	$command =~ s/[\s;]*$//g;
+	
+	my ($status, $output) = run_ssh_command($computer_node_name, $management_node_keys, $command);
+	if (!defined($output)) {
+		notify($ERRORS{'DEBUG'}, 0, "failed to run SSH command to clear the event log: @logfile_names");
+		return;
+	}
+	elsif (grep(/ERROR/i, @$output)) {
+		notify($ERRORS{'WARNING'}, 0, "failed to clear event log: @logfile_names, output:\n" . join("\n", @$output));
+		return;
+	}
+	elsif (grep(/Method execution successful/i, @$output)) {
+		notify($ERRORS{'DEBUG'}, 0, "cleared event log: @logfile_names");
+		$self->create_eventlog_entry("Event log cleared by VCL");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "unexpected output while clearing event log: @logfile_names, output:\n" . join("\n", @$output));
+		return;
+	}
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 1;
 __END__
 

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_5.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_5.pm?rev=1022187&r1=1022186&r2=1022187&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_5.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_5.pm Wed Oct 13 16:58:52 2010
@@ -273,31 +273,14 @@ sub run_sysprep {
 	# Run Sysprep.exe, use cygstart to lauch the .exe and return immediately
 	my $sysprep_command = "/bin/cygstart.exe cmd.exe /c \"";
 	
-	# First enable DHCP on the private and public interfaces and delete the default route
-	my $private_interface_name = $self->get_private_interface_name();
-	my $public_interface_name = $self->get_public_interface_name();
-	if (!$private_interface_name || !$public_interface_name) {
-		notify($ERRORS{'WARNING'}, 0, "unable to determine private and public interface names, failed to enable DHCP and shut down $computer_node_name");
-		return;
-	}
-	
-	# Release any DHCP addresses and delete the default route
-	$sysprep_command .= "$system32_path/ipconfig.exe /release & ";
-	$sysprep_command .= "$system32_path/route.exe DELETE 0.0.0.0 MASK 0.0.0.0 & ";
-	
-	# Disable DHCP
-	$sysprep_command .= "$system32_path/netsh.exe interface ip set address name=\\\"$private_interface_name\\\" source=dhcp & ";
-	$sysprep_command .= "$system32_path/netsh.exe interface ip set dns name=\\\"$private_interface_name\\\" source=dhcp & ";
-	$sysprep_command .= "$system32_path/netsh.exe interface ip set address name=\\\"$public_interface_name\\\" source=dhcp & ";
-	$sysprep_command .= "$system32_path/netsh.exe interface ip set dns name=\\\"$public_interface_name\\\" source=dhcp & ";
-	
 	# Run Sysprep.exe
 	$sysprep_command .= "C:/Sysprep/sysprep.exe /quiet /reseal /mini /forceshutdown & ";
 	
 	# Shutdown the computer - Sysprep does not always shut the computer down automatically
 	# Check if tsshutdn.exe exists on the computer
 	# tsshutdn.exe is the preferred utility, shutdown.exe often fails on Windows Server 2003
-	if ($self->file_exists("$system32_path/tsshutdn.exe")) {
+	my $windows_product_name = $self->get_product_name() || '';
+	if ($windows_product_name =~ /2003/ && $self->file_exists("$system32_path/tsshutdn.exe")) {
 		$sysprep_command .= "$system32_path/tsshutdn.exe 0 /POWERDOWN /DELAY:0 /V";
 	}
 	else {
@@ -333,12 +316,27 @@ sub run_sysprep {
 		notify($ERRORS{'OK'}, 0, "unable to determine power status of $computer_node_name from provisioning module, sleeping 5 minutes to allow computer time to power off");
 		sleep 300;
 	}
-	elsif (!$power_off) {
+	elsif ($power_off) {
+		notify($ERRORS{'OK'}, 0, "$computer_node_name powered off after running Sysprep.exe");
+		return 1;
+	}
+	else {
 		notify($ERRORS{'WARNING'}, 0, "$computer_node_name never powered off after running sysprep.exe");
-		return;
 	}
 	
-	return 1;
+	# Computer never powered off, check if provisioning module can forcefully power off the computer
+	if (!$self->provisioner->can('power_off')) {
+		notify($ERRORS{'OK'}, 0, "provisioning module does not implement a power_off subroutine");
+		return 1;
+	}
+	elsif ($self->provisioner->power_off()) {
+		notify($ERRORS{'OK'}, 0, "forcefully powered off $computer_node_name");
+		return 1;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to forcefully power off $computer_node_name");
+		return 0;
+	}
 }
 
 #/////////////////////////////////////////////////////////////////////////////