Author: arkurth
Date: Wed Nov 18 16:20:53 2009
New Revision: 881826
URL: http://svn.apache.org/viewvc?rev=881826&view=rev
Log:
VCL-260
Added Windows.pm::set_file_owner() subroutine. Added calls to set root as the
owner of /root in pre_capture() and post_load().
VCL-259
Added call to disable the ntsyslog service in Windows.pm::pre_capture(). This
service was used to send event log messages to syslog on the management node
and isn't used anymore. The service is no longer being properly configured and
can cause problems if it attempts to send messages to an address it can't get
to.
VCL-261
Reworked output/exit status checking in Windows.pm filesystem_entry_exists() so
that it first checks if the output contains "file not found" rather than
checking the exit status first. This should be more reliable.
VCL-269
Reworked Windows.pm::logoff_users() to check for disconnected sessions in
addition to logged in sessions.
VCL-262
Updated Windows.pm::apply_security_templates() to use the "/overwrite /quiet"
secedit.exe switches instead of "/verbose". This causes the .inf file being
applied to overwrite existing settings rather than append to them. It is needed
to remove the "log on as a service" permission from overwriting existing
accounts with this permission.
Other:
Increased the amount of time Windows.pm::reboot() will wait for ping to respond
from 4 to 6 minutes. 4 is too short under some circumstances.
Added check to Windows.pm::copy_capture_configuration_files() to check if the
source configuration directory in .../tools on the management node exists
before attempting to copy it to the node.
Added path to Windows.pm::clean_hard_drive(): /home/root/%USERPROFILE%. This
directory is occasionally created by some Cygwin SSH operation. I'm not sure
where it's coming from but the directory is not needed.
Modified:
incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.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=881826&r1=881825&r2=881826&view=diff
==============================================================================
--- incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ incubator/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Wed Nov 18
16:20:53 2009
@@ -172,6 +172,17 @@
=item *
+ Set root as the owner of /home/root
+
+=cut
+
+ if (!$self->set_file_owner('/home/root', 'root')) {
+ notify($ERRORS{'WARNING'}, 0, "unable to set root as the owner
of /home/root");
+ return 0;
+ }
+
+=item *
+
Copy the capture configuration files to the computer (scripts, utilities,
drivers...)
=cut
@@ -194,6 +205,17 @@
=item *
+ Disable ntsyslog service if it exists on the computer - it can prevent Cygwin
sshd from working
+
+=cut
+
+ if ($self->service_exists('ntsyslog') &&
!$self->set_service_startup_mode('ntsyslog', 'disabled')) {
+ notify($ERRORS{'WARNING'}, 0, "unable to set ntsyslog service
startup mode to disabled");
+ return 0;
+ }
+
+=item *
+
Disable IPv6
=cut
@@ -452,6 +474,16 @@
=item *
+ Set root as the owner of /home/root
+
+=cut
+
+ if (!$self->set_file_owner('/home/root', 'root')) {
+ notify($ERRORS{'WARNING'}, 0, "unable to set root as the owner
of /home/root");
+ }
+
+=item *
+
Set the Cygwin SSHD service startup mode to automatic
The Cygwin SSHD service startup mode should be set to automatic after an image
@@ -1145,14 +1177,14 @@
# Assemble the dir command and execute it
my $dir_command = "cmd.exe /c dir /a /b \"$path\"";
my ($dir_exit_status, $dir_output) =
run_ssh_command($computer_node_name, $management_node_keys, $dir_command, '',
'', 1);
- if ((defined($dir_exit_status) && $dir_exit_status == 0) ||
(defined($dir_output) && grep(/$path/i, @$dir_output))) {
+ if (defined($dir_output) && grep(/file not found/i, @$dir_output)) {
+ notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on
$computer_node_name: $path");
+ return 0;
+ }
+ elsif ((defined($dir_exit_status) && $dir_exit_status == 0) ||
(defined($dir_output) && grep(/$path/i, @$dir_output))) {
notify($ERRORS{'DEBUG'}, 0, "filesystem entry exists on
$computer_node_name: $path, dir output:\n" . join("\n", @$dir_output));
return 1;
}
- elsif ((defined($dir_exit_status) && $dir_exit_status == 1) ||
(defined($dir_output) && grep(/file not found/i, @$dir_output))) {
- notify($ERRORS{'DEBUG'}, 0, "filesystem entry does NOT exist on
$computer_node_name: $path\noutput:\n" . join("\n", @$dir_output));
- return 0;
- }
elsif ($dir_exit_status) {
notify($ERRORS{'WARNING'}, 0, "failed to determine if
filesystem entry exists on $computer_node_name: $path, exit status:
$dir_exit_status, output:\...@{$dir_output}");
return;
@@ -1165,6 +1197,69 @@
#/////////////////////////////////////////////////////////////////////////////
+=head2 set_file_owner
+
+ Parameters : file path, owner
+ Returns : If successful: true
+ If failed: false
+ Description : Recursively sets the owner of the file path. The file path can
+ be a file or directory. The owner must be a valid user account.
A
+ group can optionally be specified by appending a semicolon and
+ the group name to the owner.
+ Examples:
+ set_file_owner('/home/root', 'root')
+ set_file_owner('/home/root', 'root:Administrators')
+
+=cut
+
+sub set_file_owner {
+ 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;
+ }
+
+ # Get the file path argument
+ my $file_path = shift;
+ if (!$file_path) {
+ notify($ERRORS{'WARNING'}, 0, "file path argument was not
specified");
+ return;
+ }
+
+ # Get the owner argument
+ my $owner = shift;
+ if (!$owner) {
+ notify($ERRORS{'WARNING'}, 0, "owner argument was not
specified");
+ return;
+ }
+
+ my $management_node_keys = $self->data->get_management_node_keys();
+ my $computer_node_name = $self->data->get_computer_node_name();
+
+ # Run chown
+ my ($chown_exit_status, $chown_output) =
run_ssh_command($computer_node_name, $management_node_keys, "/usr/bin/chown.exe
-R \"$owner\" \"$file_path\"", '', '', 0);
+ my @chown_errors = grep(/(chown:|cannot access|no such file|failed
to)/ig, @$chown_output) if @$chown_output;
+ if (defined($chown_exit_status) && $chown_exit_status == 0 &&
!...@chown_errors) {
+ notify($ERRORS{'OK'}, 0, "set $owner as the owner of
$file_path");
+ }
+ elsif (@chown_errors) {
+ notify($ERRORS{'WARNING'}, 0, "error occurred setting $owner as
the owner of $file_path, error output:\n" . join("\n", @chown_errors));
+ return;
+ }
+ elsif ($chown_output) {
+ notify($ERRORS{'WARNING'}, 0, "error occurred setting $owner as
the owner of $file_path, exit status: $chown_exit_status,
output:\...@{$chown_output}");
+ return;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to run SSH command to set
$owner as the owner of $file_path");
+ return;
+ }
+
+ return 1;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
=head2 logoff_users
Parameters :
@@ -1192,41 +1287,37 @@
notify($ERRORS{'WARNING'}, 0, "failed to run qwinsta.exe SSH
command on $computer_node_name");
return;
}
-
- my @active_user_lines = grep(/Active/, @{$output});
-
- return 1 if !...@active_user_lines;
-
- notify($ERRORS{'OK'}, 0, "users are currently logged in on
$computer_node_name:\...@active_user_lines");
- #>rdp-tcp#1 root 0 Active rdpwd
- foreach my $active_user_line (@active_user_lines) {
- $active_user_line =~ /[\s>]*(\S+)\s+(.*\w)\s*(\d+)\s+Active.*/;
- my $session_name = $1;
- my $username = $2;
- my $session_id = $3;
-
- notify($ERRORS{'DEBUG'}, 0, "user logged in: $username, session
name: $session_name, session id: $session_id");
- #$ logoff /?
- #Terminates a session.
+
+ # Find lines with the state = Active or Disc
+ # Disc will occur if the user disconnected the RDP session but didn't
logoff
+ my @connection_lines = grep(/(Active|Disc)/, @{$output});
+ return 1 if !...@connection_lines;
+
+ #notify($ERRORS{'OK'}, 0, "connections on
$computer_node_name:\...@connection_lines");
+ # SESSIONNAME USERNAME ID STATE TYPE
DEVICE
+ # '> root 0 Disc rdpwd
'
+ # '>rdp-tcp#24 root 0 Active rdpwd
'
+ foreach my $connection_line (@connection_lines) {
+ my ($session_id) = $connection_line =~
/(\d+)\s+(?:Active|Listen|Conn|Disc)/g;
+ notify($ERRORS{'DEBUG'}, 0, "qwinsta.exe output:\nline:
'$connection_line'\nsession id: '$session_id'");
+
#LOGOFF [sessionname | sessionid] [/SERVER:servername] [/V]
# sessionname The name of the session.
# sessionid The ID of the session.
# /SERVER:servername Specifies the Terminal server containing
the user
#
session to log off (default is current).
# /V Displays information about the actions
performed.
-
- # Call logoff.exe, pass it the session name
- # Session ID fails if the ID is 0
- my ($logoff_exit_status, $logoff_output) =
run_ssh_command($computer_node_name, $management_node_keys, "logoff.exe
$session_name /V");
+ # Call logoff.exe, pass it the session
+ my ($logoff_exit_status, $logoff_output) =
run_ssh_command($computer_node_name, $management_node_keys, "logoff.exe
\"$session_id\" /V");
if ($logoff_exit_status == 0) {
- notify($ERRORS{'OK'}, 0, "logged off user: $username");
+ notify($ERRORS{'OK'}, 0, "logged off session ID:
$session_id, output:\n" . join("\n", @$logoff_output));
}
else {
- notify($ERRORS{'WARNING'}, 0, "failed to log off user:
$username, exit status: $logoff_exit_status, output:\...@{$logoff_output}");
+ notify($ERRORS{'WARNING'}, 0, "failed to log off
session ID: $session_id, exit status: $logoff_exit_status,
output:\...@{$logoff_output}");
}
- } ## end foreach my $active_user_line (@active_user_lines)
+ }
return 1;
-} ## end sub logoff_users
+}
#/////////////////////////////////////////////////////////////////////////////
@@ -2797,8 +2888,8 @@
notify($ERRORS{'DEBUG'}, 0, "$computer_node_name reboot has
begun, sleeping for 15 seconds");
sleep 15;
- # Wait maximum of 4 minutes for the computer to come back up
- if (!$self->wait_for_ping(4)) {
+ # Wait maximum of 6 minutes for the computer to come back up
+ if (!$self->wait_for_ping(6)) {
# Check if the computer was ever offline, it should
have been or else reboot never happened
notify($ERRORS{'WARNING'}, 0, "$computer_node_name
never responded to ping");
next WAIT_ATTEMPT;
@@ -5912,6 +6003,12 @@
# Copy configuration files
for my $source_configuration_directory
(@source_configuration_directories) {
+ # Check if source configuration directory exists on this
management node
+ unless (-d "$source_configuration_directory") {
+ notify($ERRORS{'OK'}, 0, "source directory does not
exist on this management node: $source_configuration_directory");
+ next;
+ }
+
notify($ERRORS{'OK'}, 0, "copying image capture configuration
files from $source_configuration_directory to $computer_node_name");
if (run_scp_command("$source_configuration_directory/*",
"$computer_node_name:$NODE_CONFIGURATION_DIRECTORY", $management_node_keys)) {
notify($ERRORS{'OK'}, 0, "copied
$source_configuration_directory directory to
$computer_node_name:$NODE_CONFIGURATION_DIRECTORY");
@@ -6227,6 +6324,7 @@
'$SYSTEMDRIVE/Documents and Settings,.*Temp\\/.*,10',
'$SYSTEMDRIVE/Documents and Settings,.*Temporary Internet
Files\\/Content.*\\/.*,10',
'$SYSTEMDRIVE,.*pagefile\\.sys,1',
+ '$SYSTEMDRIVE/cygwin/home/root,.*%USERPROFILE%,1',
);
# Attempt to stop the AFS service, needed to delete AFS files
@@ -6836,7 +6934,7 @@
notify($ERRORS{'DEBUG'}, 0, "copied file:
$computer_node_name:$inf_target_path");
# Set permission on the copied file
- if (!run_ssh_command($computer_node_name,
$management_node_keys, "/usr/bin/chmod.exe -R 644 $inf_target_path", '', '',
1)) {
+ if (!run_ssh_command($computer_node_name,
$management_node_keys, "/usr/bin/chmod.exe -R 644 $inf_target_path", '', '',
0)) {
notify($ERRORS{'WARNING'}, 0, "could not set
permissions on $inf_target_path");
}
}
@@ -6850,16 +6948,22 @@
my $secedit_db = '$SYSTEMROOT/security/Database/' .
"$inf_count\_$inf_file_root.sdb";
my $secedit_log = '$SYSTEMROOT/security/Logs/' .
"$inf_count\_$inf_file_root.log";
+ # Attempt to delete an existing log file
+ $self->delete_file($secedit_log);
+
# The inf path must use backslashes or secedit.exe will fail
$inf_target_path =~ s/\//\\\\/g;
- my $secedit_command = "$secedit_exe /configure /cfg
\"$inf_target_path\" /db $secedit_db /log $secedit_log /verbose";
+ # Run secedit.exe
+ # Note: secedit.exe returns exit status 3 if a warning occurs,
this will appear in the log file:
+ # Task is completed. Warnings occurred for some attributes
during this operation. It's ok to ignore.
+ my $secedit_command = "$secedit_exe /configure /cfg
\"$inf_target_path\" /db $secedit_db /log $secedit_log /overwrite /quiet";
my ($secedit_exit_status, $secedit_output) =
run_ssh_command($computer_node_name, $management_node_keys, $secedit_command,
'', '', 0);
- if (defined($secedit_exit_status) && $secedit_exit_status == 0)
{
+ if (defined($secedit_exit_status) && ($secedit_exit_status == 0
|| $secedit_exit_status == 3)) {
notify($ERRORS{'OK'}, 0, "ran secedit.exe to apply
$inf_file_name");
}
elsif (defined($secedit_exit_status)) {
- notify($ERRORS{'WARNING'}, 0, "failed to run
secedit.exe to apply $inf_target_path, exit status: $secedit_exit_status,
output:\...@{$secedit_output}");
+ notify($ERRORS{'WARNING'}, 0, "failed to run
secedit.exe to apply $inf_target_path, exit status: $secedit_exit_status,
output:\n" . join("\n", @$secedit_output));
$error_occurred++;
}
else {