Author: arkurth
Date: Fri Aug  4 18:22:33 2017
New Revision: 1804148

URL: http://svn.apache.org/viewvc?rev=1804148&view=rev
Log:
VCL-1069
Added call to 'w32tm.exe /unregister' early in 
Windows.pm::configure_time_synchronization. This seems to have fixed 
intermittent odd behavior.

Added optional message argument to Windows.pm::get_current_computer_time for 
debugging.

Added Version_6.pm::get_time_service_events. This was used for debugging but 
isn't actually called from the code.

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=1804148&r1=1804147&r2=1804148&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/OS/Windows.pm Fri Aug  4 18:22:33 
2017
@@ -8870,7 +8870,7 @@ sub configure_time_synchronization {
                return;
        }
        
-       my $start_time = time;
+       my $time_string_before = $self->get_current_computer_time('before 
configure_time_synchronization');
        
        my $system32_path = $self->get_system32_path() || return;
        my $computer_name = $self->data->get_computer_node_name();
@@ -8888,13 +8888,11 @@ sub configure_time_synchronization {
                $time_source_variable = 'pool.ntp.org';
        }
        
-       $self->get_current_computer_time();
-       
        my $key = 
'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers';
        
        # Delete existing key
        $self->reg_delete($key);
-       
+
        # Update the registry
        my $index = 1;
        my @time_sources = split(/[,;\s]/, $time_source_variable);
@@ -8913,19 +8911,29 @@ sub configure_time_synchronization {
                $manual_peer_list .= $time_source;
        }
        
-       #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));
-       #}
+       # Make sure the service is stopped before calling /unregister or it 
will fail
+       $self->stop_service('w32time');
+
+       # Call /unregister the time service first - calling only /register 
doesn't seem to reset everything
+       # Unexpected results may occur if this isn't done
+       $self->get_current_computer_time('before unregister');
+       my $unregister_command = "$system32_path/w32tm.exe /unregister";
+       my ($unregister_exit_status, $unregister_output) = 
$self->execute({command => $unregister_command, timeout_seconds => 20, 
max_attempts => 1, display_output => 0});
+       if (!defined($unregister_output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute command to 
unregister W32Time on $computer_name: $unregister_command");
+               return;
+       }
+       elsif ($unregister_exit_status ne '0') {
+               notify($ERRORS{'WARNING'}, 0, "failed to unregister W32Time on 
$computer_name, exit status: $unregister_exit_status, 
command:\n$unregister_command\noutput:\n" . join("\n", @$unregister_output));
+       }
+       else {
+               notify($ERRORS{'OK'}, 0, "unregistered W32Time on 
$computer_name");
+       }
+       
+       # Make sure no remnants are leftover
+       
$self->reg_delete('HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time');
        
+       # Call /register - registers w32time service and sets default 
configuration to the registry
        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)) {
@@ -8939,15 +8947,35 @@ sub configure_time_synchronization {
                notify($ERRORS{'OK'}, 0, "registered W32Time on 
$computer_name");
        }
        
+       # Uncomment the next few lines for for debugging
+       #my $debug_command = "$system32_path/w32tm.exe /debug /enable 
/file:C:/Windows/Debug/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));
+       #}
+
+       # Only care about w32tm.exe config and sync duration
+       my $start_time = time;
+       
        # 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');
        
+       # Start the service before calling /config or else /config will fail
        $self->start_service('w32time') || return;
-       
-       my $config_command = "$system32_path/w32tm.exe /config 
/manualpeerlist:\"$manual_peer_list\" /syncfromflags:manual /update";
+
+       my $config_command = "$system32_path/w32tm.exe /config 
/manualpeerlist:\"$manual_peer_list\" /syncfromflags:manual";
+       # The following argument shouldn't be necessary if the service is later 
restarted:
+       $config_command .= " /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");
@@ -8957,24 +8985,30 @@ sub configure_time_synchronization {
                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{'OK'}, 0, "configured W32Time on $computer_name 
to use time source(s): $manual_peer_list");
+               notify($ERRORS{'DEBUG'}, 0, "configured W32Time on 
$computer_name to use time source(s): $manual_peer_list");
        }
        
-       $self->restart_service('w32time') || return;
+       # Restart the service
+       # This shouldn't be necessary if the /config command above includes 
/update
+       #$self->restart_service('w32time') || return;
        
+       # Call /resync
        my $resync_command = "$system32_path/w32tm.exe /resync";
+       $resync_command .= " /force";
        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));
+       elsif (grep(/success/, @$resync_output)) {
+               notify($ERRORS{'DEBUG'}, 0, "resynchronized W32Time on 
$computer_name, output:\n" . join("\n", @$resync_output));
        }
        else {
-               notify($ERRORS{'OK'}, 0, "resync'd W32Time on $computer_name, 
output:\n" . join("\n", @$resync_output));
+               notify($ERRORS{'DEBUG'}, 0, "W32Time resynchronization may have 
failed on $computer_name:\n" . join("\n", @$resync_output));
        }
        
+       my $duration = (time - $start_time);
+       
        # Set the w32time service startup mode to auto
        if ($self->set_service_startup_mode('w32time', 'auto')) {
                notify($ERRORS{'DEBUG'}, 0, "set w32time service startup mode 
to auto");
@@ -8984,14 +9018,19 @@ sub configure_time_synchronization {
                return;
        }
        
+       # For debugging:
+       #$self->get_time_service_events() if 
$self->can('get_time_service_events');
+       
        # 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->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 $time_string_after = $self->get_current_computer_time('after 
configure_time_synchronization');
        
-       my $duration = (time - $start_time);
-       notify($ERRORS{'DEBUG'}, 0, "configure time synchronization duration: 
$duration seconds");
+       notify($ERRORS{'DEBUG'}, 0, "configured time synchronization duration: 
$duration seconds\n" .
+               "time before configuration : $time_string_before\n" .
+               "time after configuration  : $time_string_after"
+       );
        return 1;
 }
 
@@ -8999,7 +9038,7 @@ sub configure_time_synchronization {
 
 =head2 get_current_computer_time
 
- Parameters  : none
+ Parameters  : $message (optional)
  Returns     : string
  Description : Used for debugging and troubleshooting purposes. Simply displays
                the current date, time, and timezone offset according to the
@@ -9015,6 +9054,8 @@ sub get_current_computer_time {
                return;
        }
        
+       my $message = shift;
+       
        my $computer_name = $self->data->get_computer_node_name();
        
        #my $command = 'cmd.exe /c "echo %date% %time%"';
@@ -9031,7 +9072,7 @@ sub get_current_computer_time {
        
        my ($current_time) = grep(/\d:/, @$output);
        if ($current_time) {
-               notify($ERRORS{'OK'}, 0, "retrieved current time on 
$computer_name: $current_time");
+               notify($ERRORS{'OK'}, 0, "retrieved current time on 
$computer_name: $current_time ($message)");
                return $current_time;
        }
        else {

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=1804148&r1=1804147&r2=1804148&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 Fri Aug  4 
18:22:33 2017
@@ -2121,7 +2121,7 @@ sub disable_sleep {
 
 =head2 query_event_log
 
- Parameters  : $event_log_name, $xpath_query, $event_count_limit (optional)
+ Parameters  : $event_log_name, $xpath_query, $event_count_limit (optional), 
$display_output (optional)
  Returns     : array
  Description : Queries the event log on the computer. The $event_log_name
                argument refers to the 'Channel' property of the events to be
@@ -2133,6 +2133,7 @@ sub disable_sleep {
                *
                *[System[Provider[@Name="Microsoft-Windows-Security-Auditing"] 
and Task=12544 and EventID=4624] and EventData[Data[@Name="LogonType"]="10"]]
                *[System[TimeCreated[timediff(@SystemTime) <= $milliseconds]]]
+               *[System[Provider[@Name="Microsoft-Windows-Time-Service"]]]
                
                Constructs an array of hashes based on the XML output from
                wevtutil.exe.
@@ -2146,7 +2147,7 @@ sub query_event_log {
                return;
        }
        
-       my ($event_log_name, $xpath_query, $event_count_limit) = @_;
+       my ($event_log_name, $xpath_query, $event_count_limit, $display_output) 
= @_;
        if (!$event_log_name) {
                notify($ERRORS{'WARNING'}, 0, "event log name argument was not 
specified");
                return;
@@ -2206,7 +2207,26 @@ sub query_event_log {
        my @events = @{$xml_hash->{Event}};
        my $event_count = scalar(@events);
        
-       notify($ERRORS{'DEBUG'}, 0, "retrieved $event_count $event_log_name 
event" . ($event_count == 1 ? '' : 's') . " from $computer_node_name, 
command:\n$command\n" . format_data(\@events));
+       my $levels = {
+               0 => 'Undefined',
+               1 => 'Critical',
+               2 => 'Error',
+               3 => 'Warning',
+               4 => 'Information',
+               5 => 'Verbose',
+       };
+       
+       for my $event (@events) {
+               my $level = $event->{System}{Level};
+               if (defined($level) && $levels->{$level}) {
+                       $event->{System}{LEVEL_NAME} = $levels->{$level};
+               }
+               else {
+                       $event->{System}{LEVEL_NAME} = '<unknown>';
+               }
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved $event_count $event_log_name 
event" . ($event_count == 1 ? '' : 's') . " from $computer_node_name, 
command:\n$command\n" . format_data(\@events)) if $display_output;
        return @events;
 }
 
@@ -2271,6 +2291,81 @@ sub query_event_log_helper {
 }
 
 #//////////////////////////////////////////////////////////////////////////////
+
+=head2 get_time_service_events
+
+ Parameters  : none
+ Returns     : array
+ Description : Retrieves event log entries generated by the Windows Time
+               (w32time) service. Returns an array of hash references:
+                  [
+                    {
+                      "EventData" => {
+                        "Data" => {
+                          "TimeSource" => "pool.ntp.org 
(ntp.m|0x0|0.0.0.0:123-><IP Address>:123)"
+                        },
+                        "Name" => "TMP_EVENT_TIME_SOURCE_REACHABLE"
+                      },
+                      "System" => {
+                        "Channel" => "System",
+                        "Computer" => "win2012r2",
+                        "Correlation" => {},
+                        "EventID" => 37,
+                        "EventRecordID" => 3242,
+                        "Execution" => {
+                          "ProcessID" => 796,
+                          "ThreadID" => 1204
+                        },
+                        "Keywords" => "0x8000000000000000",
+                        "Level" => 4,
+                        "Opcode" => 0,
+                        "Provider" => {
+                          "Guid" => "{06EDCFEB-0FD0-4E53-ACCA-A6F8BBF81BCB}",
+                          "Name" => "Microsoft-Windows-Time-Service"
+                        },
+                        "Security" => {
+                          "UserID" => "S-1-5-19"
+                        },
+                        "Task" => 0,
+                        "TimeCreated" => {
+                          "SystemTime" => "2017-07-28T12:08:12.195010600Z"
+                        },
+                        "Version" => 0
+                      },
+                      "xmlns" => 
"http://schemas.microsoft.com/win/2004/08/events/event";
+                    },
+                    {
+                      ...
+                    },
+                  ]
+
+=cut
+
+sub get_time_service_events {
+       my $self = shift;
+       if (ref($self) !~ /VCL::Module/i) {
+               notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
+               return;
+       }
+       
+       my $computer_name = $self->data->get_computer_short_name();
+       
+       my @events = $self->query_event_log('System', 
'*[System[Provider[@Name="Microsoft-Windows-Time-Service"]]]', 100, 0);
+       
+       my $info_string;
+       for my $event (@events) {
+               my $level = $event->{System}{LEVEL_NAME};
+               my $system_time = $event->{System}{TimeCreated}{SystemTime};
+               my $event_name = $event->{EventData}{Name};
+               my $event_data = $event->{EventData}{Data};
+               $info_string .= "($level) $system_time - $event_name\n" . 
format_data($event_data) . "\n\n";
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved time service entries from event 
log on $computer_name:\n$info_string");
+       return @events;
+}
+
+#//////////////////////////////////////////////////////////////////////////////
 
 =head2 get_logon_events
 


Reply via email to