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:\...@{$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;
}