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;
 }
 


Reply via email to