Author: arkurth
Date: Wed Aug 2 20:28:42 2017
New Revision: 1803917
URL: http://svn.apache.org/viewvc?rev=1803917&view=rev
Log:
VCL-1069
Added command to set MaxPosPhaseCorrection and MaxNegPhaseCorrection registry
keys before time synchronization is configured in
Windows.pm::configure_time_synchronization. Cleaned up the subroutine.
Added Windows.pm::get_current_computer_time which is only used for
troubleshooting. Added call to this in Version_6.pm::activate if activation
fails to help determine if failure was caused by incorrect time on the client.
Modified:
vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm
URL:
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm?rev=1803917&r1=1803916&r2=1803917&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Wed Aug 2 20:28:42
2017
@@ -3061,7 +3061,7 @@ sub reg_add {
return;
}
elsif ($add_registry_exit_status == 0) {
- notify($ERRORS{'DEBUG'}, 0, "added registry key: $registry_key,
output:\n" . join("\n", @$add_registry_output));
+ notify($ERRORS{'DEBUG'}, 0, "added registry key, command:
$add_registry_command, output:\n" . join("\n", @$add_registry_output));
return 1;
}
else {
@@ -8833,8 +8833,7 @@ sub get_volume_list {
=head2 configure_time_synchronization
Parameters : None
- Returns : If successful: true
- If failed: false
+ Returns : boolean
Description : Configures the Windows Time service and synchronizes the time.
=cut
@@ -8846,65 +8845,110 @@ sub configure_time_synchronization {
return;
}
+ my $start_time = time;
+
my $system32_path = $self->get_system32_path() || return;
+ my $computer_name = $self->data->get_computer_node_name();
- my $time_source;
+ my $time_source_variable;
my $variable_name = "timesource|" .
$self->data->get_management_node_hostname();
my $variable_name_global = "timesource|global";
if (is_variable_set($variable_name)) {
- $time_source = get_variable($variable_name);
- notify($ERRORS{'DEBUG'}, 0, "time_source is $time_source set
for $variable_name");
+ $time_source_variable = get_variable($variable_name);
}
elsif (is_variable_set($variable_name_global)) {
- $time_source = get_variable($variable_name_global);
- notify($ERRORS{'DEBUG'}, 0, "time_source is $time_source set
for $variable_name");
+ $time_source_variable = get_variable($variable_name_global);
}
else {
- $time_source = "time.nist.gov time-a.nist.gov time-b.nist.gov
time.windows.com";
- notify($ERRORS{'DEBUG'}, 0, "time_source is not set for
$variable_name using hardcoded values of $time_source");
+ $time_source_variable = 'pool.ntp.org';
}
- # Replace commas with single whitespace
- $time_source =~ s/,/ /g;
- my @time_array = split(/ /, $time_source);
+ $self->get_current_computer_time();
- # Update the registry
my $key =
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers';
- for my $i (0 .. $#time_array) {
- my $value = $i+1;
- $self->reg_add($key,$value, "REG_SZ", $time_array[$i]);
- }
- # Assemble the time command
- my $time_command;
+ # Delete existing key
+ $self->reg_delete($key);
+
+ # Update the registry
+ my $index = 1;
+ my @time_sources = split(/[,;\s]/, $time_source_variable);
+ my $manual_peer_list;
+ for my $time_source (@time_sources) {
+ # Remove leading and trailing spaces
+ $time_source =~ s/(^\s+|\s+$)//g;
+
+ # Make sure it isn't blank
+ next unless $time_source =~ /\S/;
+
+ $self->reg_add($key, $index, "REG_SZ", $time_source);
+ $index++;
+
+ $manual_peer_list .= ' ' if $manual_peer_list;
+ $manual_peer_list .= $time_source;
+ }
- # Kill d4.exe if it's running, this will prevent Windows built-in time
synchronization from working
- $time_command .= "$system32_path/taskkill.exe /IM d4.exe /F 2>/dev/null
; ";
+ #my $debug_command = "$system32_path/w32tm.exe /debug /enable
/file:C:/w32tm.log /size:1024000000 /entries:0-300";
+ #my ($debug_exit_status, $debug_output) = $self->execute({command =>
$debug_command, timeout_seconds => 20, max_attempts => 1, display_output => 0});
+ #if (!defined($debug_output)) {
+ # notify($ERRORS{'WARNING'}, 0, "failed to execute command to
enable W32Time debugging on $computer_name: $debug_command");
+ # return;
+ #}
+ #elsif ($debug_exit_status ne '0') {
+ # notify($ERRORS{'WARNING'}, 0, "failed to enable W32Time
debugging on $computer_name, exit status: $debug_exit_status,
command:\n$debug_command\noutput:\n" . join("\n", @$debug_output));
+ #}
+ #else {
+ # notify($ERRORS{'OK'}, 0, "enabled W32Time debugging on
$computer_name, output:\n" . join("\n", @$debug_output));
+ #}
- # Register the w32time service
- $time_command .= "$system32_path/w32tm.exe /register ; ";
+ my $register_command = "$system32_path/w32tm.exe /register";
+ my ($register_exit_status, $register_output) = $self->execute({command
=> $register_command, timeout_seconds => 20, max_attempts => 1, display_output
=> 0});
+ if (!defined($register_output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command to
register W32Time on $computer_name: $register_command");
+ return;
+ }
+ elsif ($register_exit_status ne '0') {
+ notify($ERRORS{'WARNING'}, 0, "failed to register W32Time on
$computer_name, exit status: $register_exit_status,
command:\n$register_command\noutput:\n" . join("\n", @$register_output));
+ }
+ else {
+ notify($ERRORS{'OK'}, 0, "registered W32Time on
$computer_name");
+ }
- # Start the service and configure it
- $time_command .= "$system32_path/net.exe start w32time 2>/dev/null ; ";
- $time_command .= "$system32_path/w32tm.exe /config
/manualpeerlist:\"$time_source\" /syncfromflags:manual /update ; ";
- $time_command .= "$system32_path/net.exe stop w32time &&
$system32_path/net.exe start w32time ; ";
+ # By default, Windows time service will only allow the time to be
changes by 15 hours (54,000 seconds) or less
+ # Set the following keys to allow any time adjustment
+ # This must be done after w32tm.exe /register because that command will
reset the values to the defaults
+
$self->reg_add('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config',
'MaxPosPhaseCorrection', 'REG_DWORD', '0xFFFFFFFF');
+
$self->reg_add('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config',
'MaxNegPhaseCorrection', 'REG_DWORD', '0xFFFFFFFF');
- # Synchronize the time
- $time_command .= "$system32_path/w32tm.exe /resync /nowait";
+ $self->start_service('w32time') || return;
- # Run the assembled command
- my ($time_exit_status, $time_output) = $self->execute($time_command);
- if (defined($time_output) && @$time_output[-1] =~ /The command
completed successfully/i) {
- notify($ERRORS{'DEBUG'}, 0, "configured and synchronized
Windows time");
- }
- elsif (defined($time_exit_status)) {
- notify($ERRORS{'WARNING'}, 0, "failed to configure configure
and synchronize Windows time, exit status: $time_exit_status,
output:\n@{$time_output}");
+ my $config_command = "$system32_path/w32tm.exe /config
/manualpeerlist:\"$manual_peer_list\" /syncfromflags:manual /update";
+ my ($config_exit_status, $config_output) = $self->execute({command =>
$config_command, timeout_seconds => 20, max_attempts => 1, display_output =>
0});
+ if (!defined($config_output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command to
configure W32Time on $computer_name: $config_command");
return;
}
+ elsif ($config_exit_status ne '0') {
+ notify($ERRORS{'WARNING'}, 0, "failed to configure W32Time on
$computer_name to use time source(s): $manual_peer_list, exit status:
$config_exit_status, command:\n$config_command\noutput:\n" . join("\n",
@$config_output));
+ }
else {
- notify($ERRORS{'WARNING'}, 0, "failed to run ssh command to
configure and synchronize Windows time");
+ notify($ERRORS{'OK'}, 0, "configured W32Time on $computer_name
to use time source(s): $manual_peer_list");
+ }
+
+ #$self->restart_service('w32time') || return;
+
+ my $resync_command = "$system32_path/w32tm.exe /resync /nowait";
+ my ($resync_exit_status, $resync_output) = $self->execute({command =>
$resync_command, timeout_seconds => 20, max_attempts => 1, display_output =>
0});
+ if (!defined($resync_output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command to
resync W32Time on $computer_name: $resync_command");
return;
}
+ elsif ($resync_exit_status ne '0') {
+ notify($ERRORS{'WARNING'}, 0, "failed to resync W32Time on
$computer_name, exit status: $resync_exit_status,
command:\n$resync_command\noutput:\n" . join("\n", @$resync_output));
+ }
+ else {
+ notify($ERRORS{'OK'}, 0, "resync'd W32Time on $computer_name,
output:\n" . join("\n", @$resync_output));
+ }
# Set the w32time service startup mode to auto
if ($self->set_service_startup_mode('w32time', 'auto')) {
@@ -8915,10 +8959,63 @@ sub configure_time_synchronization {
return;
}
+ # Set the maximum time change parameters back to the defaults for
security
+
$self->reg_add('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config',
'MaxPosPhaseCorrection', 'REG_DWORD', 50000000);
+
$self->reg_add('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config',
'MaxNegPhaseCorrection', 'REG_DWORD', 50000000);
+
+ $self->get_current_computer_time();
+
+ my $duration = (time - $start_time);
+ notify($ERRORS{'DEBUG'}, 0, "configure time synchronization duration:
$duration seconds");
return 1;
}
#//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_current_computer_time
+
+ Parameters : none
+ Returns : string
+ Description : Used for debugging and troubleshooting purposes. Simply displays
+ the current date, time, and timezone offset according to the
+ computer. Example:
+ 2017-08-02 11:35:32 PDT -07:00
+
+=cut
+
+sub get_current_computer_time {
+ my $self = shift;
+ unless (ref($self) && $self->isa('VCL::Module')) {
+ notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called
as a VCL::Module module object method");
+ return;
+ }
+
+ my $computer_name = $self->data->get_computer_node_name();
+
+ #my $command = 'cmd.exe /c "echo %date% %time%"';
+ my $command = 'date +"%Y-%m-%d %H:%M:%S %Z %:z"';
+ my ($exit_status, $output) = $self->execute({command => $command,
max_attempts => 1, display_output => 0});
+ if (!defined($output)) {
+ notify($ERRORS{'WARNING'}, 0, "failed to execute command to
retrieve current time on $computer_name: $command");
+ return;
+ }
+ elsif ($exit_status ne '0') {
+ notify($ERRORS{'WARNING'}, 0, "failed to retrieve current time
on $computer_name, exit status: $exit_status, command:\n$command\noutput:\n" .
join("\n", @$output));
+ return 0;
+ }
+
+ my ($current_time) = grep(/\d:/, @$output);
+ if ($current_time) {
+ notify($ERRORS{'OK'}, 0, "retrieved current time on
$computer_name: $current_time");
+ return $current_time;
+ }
+ else {
+ notify($ERRORS{'WARNING'}, 0, "failed to parse output in order
to retrieve current time on $computer_name, exit status: $exit_status,
command:\n$command\noutput:\n" . join("\n", @$output));
+ return;
+ }
+}
+
+#//////////////////////////////////////////////////////////////////////////////
=head2 is_64_bit
Modified: vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm
URL:
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm?rev=1803917&r1=1803916&r2=1803917&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows/Version_6.pm Wed Aug 2
20:28:42 2017
@@ -255,6 +255,10 @@ sub activate {
return 1;
}
else {
+ # Display the computer's current time in vcld.log to help
diagnose the problem
+ # Activation fails if the client's time is incorrect
+ $self->get_current_computer_time();
+
notify($ERRORS{'CRITICAL'}, 0, "failed to activate Windows
using MAK or KMS methods");
return;
}