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 2009/09/25 21:41:40 UTC

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

Author: arkurth
Date: Fri Sep 25 19:41:39 2009
New Revision: 818973

URL: http://svn.apache.org/viewvc?rev=818973&view=rev
Log:
VCL-212
Updated Version_6.pm::run_sysprep() to reset some registry keys which prevent Sysprep from running if Sysprep had failed before.  Improved the cleanup tasks in this subroutine so that old logs are deleted before running Sysprep.  Changed the behavior after Sysprep is executed to detect unresponsiveness and power off instead of waiting for a fixed 180 seconds.

Added reg_add() to Windows.pm.  This gets called by Version_6.pm::run_sysprep().

Modified:
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
    incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.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=818973&r1=818972&r2=818973&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Fri Sep 25 19:41:39 2009
@@ -2108,6 +2108,86 @@
 
 #/////////////////////////////////////////////////////////////////////////////
 
+=head2 reg_add
+
+ Parameters  : key, value, type, data
+ Returns     : If successful: true
+               If failed: false
+ Description : Adds or sets a registry key.
+
+=cut
+
+sub reg_add {
+	my $self = shift;
+	if (ref($self) !~ /windows/i) {
+		notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
+		return;
+	}
+
+	my $management_node_keys = $self->data->get_management_node_keys();
+	my $computer_node_name   = $self->data->get_computer_node_name();
+	
+	# Get the arguments
+	my $registry_key = shift;
+	if (!defined($registry_key) || !$registry_key) {
+		notify($ERRORS{'WARNING'}, 0, "registry key was not passed correctly as an argument");
+		return;
+	}
+	
+	my $registry_value = shift;
+	if (!defined($registry_value) || !$registry_value) {
+		notify($ERRORS{'WARNING'}, 0, "registry value was not passed correctly as an argument");
+		return;
+	}
+	
+	my $registry_type = shift;
+	if (!defined($registry_type) || !$registry_type) {
+		notify($ERRORS{'WARNING'}, 0, "registry type was not passed correctly as an argument");
+		return;
+	}
+	if ($registry_type !~ /^(REG_SZ|REG_MULTI_SZ|REG_DWORD_BIG_ENDIAN|REG_DWORD|REG_BINARY|REG_DWORD_LITTLE_ENDIAN|REG_NONE|REG_EXPAND_SZ)$/) {
+		notify($ERRORS{'WARNING'}, 0, "invalid registry type was specified: $registry_type");
+		return;
+	}
+	
+	my $registry_data = shift;
+	if (!defined($registry_data) || !$registry_data) {
+		notify($ERRORS{'WARNING'}, 0, "registry data was not passed correctly as an argument");
+		return;
+	}
+	
+	# Fix the value parameter to allow 'default' to be specified
+	my $value_parameter;
+	if ($registry_value =~ /^default$/i) {
+		$value_parameter = '/ve';
+	}
+	else {
+		$value_parameter = "/v \"$registry_value\"";
+	}
+	
+	# Replace forward slashes with backslashes in registry key
+	$registry_key =~ s/\//\\\\/g;
+	
+	# Run reg.exe ADD
+	my $add_registry_command = $self->get_system32_path() . "/reg.exe ADD \"$registry_key\" $value_parameter /t $registry_type /d \"$registry_data\" /f";
+	my ($add_registry_exit_status, $add_registry_output) = run_ssh_command($computer_node_name, $management_node_keys, $add_registry_command, '', '', 1);
+	if (defined($add_registry_exit_status) && $add_registry_exit_status == 0) {
+		notify($ERRORS{'DEBUG'}, 0, "added registry key: $registry_key, output:\n" . join("\n", @$add_registry_output));
+	}
+	elsif ($add_registry_exit_status) {
+		notify($ERRORS{'WARNING'}, 0, "failed to add registry key: $registry_key, value: $registry_value, exit status: $add_registry_exit_status, output:\n@{$add_registry_output}");
+		return;
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to add registry key: $registry_key, value: $registry_value");
+		return;
+	}
+	
+	return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
 =head2 reg_delete
 
  Parameters  : registry key, registry value

Modified: incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm
URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm?rev=818973&r1=818972&r2=818973&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm Fri Sep 25 19:41:39 2009
@@ -1269,27 +1269,42 @@
 	my $system32_path_dos = $system32_path;
 	$system32_path_dos =~ s/\//\\/g;
 	
-	# Delete existing setupapi files (log files generated by Sysprep)
+	# Delete existing Panther directory, contains Sysprep log files
+	if (!$self->delete_file('C:/Windows/Panther')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to delete Panther directory, Sysprep will proceed");
+	}
+	
+	# Delete existing sysprep/Panther directory, contains Sysprep log files
+	if (!$self->delete_file("$system32_path/sysprep/Panther")) {
+		notify($ERRORS{'WARNING'}, 0, "unable to delete Sysprep Panther directory, Sysprep will proceed");
+	}
+	
+	# Delete existing setupapi files
 	if (!$self->delete_file('C:/Windows/inf/setupapi*')) {
-		notify($ERRORS{'WARNING'}, 0, "unable to delete setupapi log files, Sysprep will proceed");
+		notify($ERRORS{'WARNING'}, 0, "unable to delete setupapi files, Sysprep will proceed");
 	}
-
+	
+	# Delete existing INFCACHE files
+	if (!$self->delete_file('C:/Windows/inf/INFCACHE*')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to delete INFCACHE files, Sysprep will proceed");
+	}
+	
+	# Delete existing INFCACHE files
+	if (!$self->delete_file('C:/Windows/inf/oem*.inf')) {
+		notify($ERRORS{'WARNING'}, 0, "unable to delete INFCACHE files, Sysprep will proceed");
+	}
+	
 	# Delete existing Sysprep_succeeded.tag file
 	if (!$self->delete_file("$system32_path/sysprep/Sysprep*.tag")) {
 		notify($ERRORS{'WARNING'}, 0, "unable to delete Sysprep_succeeded.tag log file, Sysprep will proceed");
 	}
-
-	# Delete existing Panther directory, contains Sysprep log files
-	if (!$self->delete_file("$system32_path/sysprep/Panther")) {
-		notify($ERRORS{'WARNING'}, 0, "unable to delete Sysprep Panther directory, Sysprep will proceed");
-	}
-
-	# Delete existing Panther directory, contains Sysprep log files
+	
+	# Delete existing Unattend.xml file
 	if (!$self->delete_file("$system32_path/sysprep/Unattend.xml")) {
 		notify($ERRORS{'WARNING'}, 0, "unable to delete Sysprep Unattend.xml file, Sysprep will NOT proceed");
 		return;
 	}
-
+	
 	# Copy Unattend.xml file to sysprep directory
 	my $node_configuration_directory = $self->get_node_configuration_directory();
 	my $cp_command = "cp -f $node_configuration_directory/Utilities/Sysprep/Unattend.xml $system32_path/sysprep/Unattend.xml";
@@ -1305,7 +1320,47 @@
 		notify($ERRORS{'WARNING'}, 0, "unable to run ssh command to copy Unattend.xml to $system32_path/sysprep");
 		return;
 	}
+	
+	# Get the node drivers directory and convert it to DOS format
+	my $drivers_directory = $self->get_node_configuration_directory() . '/Drivers';
+	$drivers_directory =~ s/\//\\\\/g;
+	
+	# Set the Installation Sources registry key
+	# Must use reg_add because the type is REG_MULTI_SZ
+	my $setup_key = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup';
+	if ($self->reg_add($setup_key, 'Installation Sources', 'REG_MULTI_SZ', $drivers_directory)) {
+		notify($ERRORS{'DEBUG'}, 0, "added Installation Sources registry key");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to add Installation Sources registry key");
+	}
+	
+	# Reset the Windows setup registry keys
+	# If Sysprep fails it will set keys which make running Sysprep again impossible
+	# These keys never get reset, Microsoft instructs you to reinstall the OS
+	# Clearing out these keys before running Sysprep allows it to be run again
+	# Also enable verbose Sysprep logging
+	my $registry_string .= <<"EOF";
+Windows Registry Editor Version 5.00
+
+[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup]
+"LogLevel"=dword:0000FFFF
 
+[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State]
+"ImageState"="IMAGE_STATE_COMPLETE"
+
+[-HKEY_LOCAL_MACHINE\\SYSTEM\\Setup\\Status]
+EOF
+	
+	# Import the string into the registry
+	if ($self->import_registry_string($registry_string)) {
+		notify($ERRORS{'OK'}, 0, "reset Windows setup state in the registry");
+	}
+	else {
+		notify($ERRORS{'WARNING'}, 0, "failed to reset the Windows setup state in the registry");
+		return 0;
+	}
+	
 	# Run Sysprep.exe, use cygstart to lauch the .exe and return immediately
 	my $sysprep_command = '/bin/cygstart.exe cmd.exe /c "' . $system32_path_dos . '\\sysprep\\sysprep.exe /generalize /oobe /shutdown /quiet"';
 	my ($sysprep_status, $sysprep_output) = run_ssh_command($computer_node_name, $management_node_keys, $sysprep_command);
@@ -1328,18 +1383,22 @@
 		return 0;
 	}
 	
-	# Wait for 3 minutes then call provisioning module's power_off() subroutine
-	# Sysprep does not always shut down the computer when it is done
-	notify($ERRORS{'OK'}, 0, "sleeping for 3 minutes to allow Sysprep.exe to finish");
-	sleep 180;
-
-	# Call power_off() to make sure computer is shut down
-	if (!$self->provisioner->power_off()) {
-		# Computer could not be shut off
-		notify($ERRORS{'WARNING'}, 0, "unable to power off $computer_node_name");
-		return 0;
+	# Wait for Sysprep to power off the computer
+	# If Sysprep fails to power off the computer, forcefully power it off
+	if ($self->provisioner->wait_for_off(3)) {
+		notify($ERRORS{'DEBUG'}, 0, "$computer_node_name was powered off by Sysprep");
 	}
-
+	else {
+		notify($ERRORS{'WARNING'}, 0, "$computer_node_name was NOT powered off by Sysprep");
+		
+		# Call power_off() to make sure computer is shut down
+		if (!$self->provisioner->power_off()) {
+			# Computer could not be shut off
+			notify($ERRORS{'WARNING'}, 0, "unable to power off $computer_node_name");
+			return 0;
+		}
+	}
+	
 	return 1;
 }