Created
August 20, 2009 10:58
-
-
Save eqhmcow/170984 to your computer and use it in GitHub Desktop.
script that automatically resets a virtual machine's system time after the host resumes from sleep. This is handy e.g. when using vmware on a laptop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
=pod | |
check_time.pl | |
This script automatically resets a virtual machine's system time after the | |
host resumes from sleep. This is handy e.g. when using vmware on a laptop. | |
The NTP daemon is stopped and the system time is immediately set from the | |
hardware clock if the hardware clock is more than a few seconds in the future. | |
After setting system time, the script runs ntpdate and finally restarts the | |
NTP daemon. This ensures the proper time is set even if the guest doesn't have | |
network connectivity, while also allowing NTP to resume maintaining the | |
system clock as quickly as possible. | |
When the host suspends, so does the guest; on resume, the guest system time | |
will be the time when the host suspended, which will be much earlier than | |
the host clock. This script checks the clock every minute to ensure the | |
guest system time is automatically reset to the correct time soon after a | |
resume. In combination with ntpd, this is superior to forced periodic host | |
to guest time synchronization; ntpd will keep the guest clock properly set | |
while the system is running, and forced syncs will only occur after the host | |
resumes from sleep. | |
This script is meant to be run as a daemon. Add the following line to your | |
rc.local or equivalent startup file: | |
nohup /usr/local/bin/check_time.pl & | |
=cut | |
# configurable settings | |
# how often to check the time, in seconds | |
my $check_every = 60; # seconds | |
# system log entry if the hardware clock is out of sync | |
my $log_if_delta_larger_than = 1; # seconds | |
# reset system time if hardware clock is out of sync | |
my $reset_if_delta_larger_than = 5; # seconds | |
# list of NTP servers that ntpdate will attempt to use | |
# servers are tried in order until ntpdate is successful or we run out | |
# we only try once per server. | |
# list local servers (if any) first | |
my @ntp_servers = qw/ | |
wingfly | |
0.north-america.pool.ntp.org | |
1.north-america.pool.ntp.org | |
2.north-america.pool.ntp.org | |
3.north-america.pool.ntp.org | |
ntp.apple.com | |
ntp.ubuntu.com | |
time.windows.com | |
/; | |
use Date::Parse; | |
use Time::HiRes 'time'; | |
while (1) { | |
check_time(); | |
sleep $check_every; | |
} | |
sub check_time | |
{ | |
my $initial_time = time; | |
my $hw_time = `hwclock --show`; | |
my $time = time; | |
($hw_time, my $adj) = $hw_time =~ m/^(.*\S)\s+(\S+) seconds$/; | |
$hw_time = str2time($hw_time); | |
#print "initl time: $initial_time\n"; | |
#print "local time: $time\n"; | |
my $local_sec = $time; | |
$local_sec =~ s/^[^.]+(\..*)$/$1/; | |
$hw_time = $hw_time . $local_sec; | |
$hw_time += $adj; | |
#print "hware time: $hw_time\n"; | |
my $delta = $hw_time - $initial_time; | |
#print "delta: $delta\n"; | |
# we shouldn't be more than a second off hardware clock if ntpd is working | |
# on both the host and the guest | |
`logger -- $0 delta $delta` if abs $delta > $log_if_delta_larger_than; | |
# hardware clock will be quite a bit in the future if we've been sleeping | |
return 0 unless $delta > $reset_if_delta_larger_than; | |
`logger -- $0 delta too large [$delta \\> $reset_if_delta_larger_than], resetting clock`; | |
# using sudo allows this script to run without root if you so desire | |
# sudo also logs the exact commands the script runs | |
my $msg = `sudo /etc/init.d/ntp stop`; | |
`logger -- $0 ntp stop '$msg'`; | |
$msg = `sudo hwclock --hctosys`; | |
`logger -- $0 hwclock --hctosys '$msg'`; | |
foreach my $ntp_server (@ntp_servers) { | |
sleep 5; # wait a bit in case the network is slow to come up | |
$msg = `sudo ntpdate '$ntp_server'`; | |
my $result = $? >> 8; | |
`logger -- $0 ntpdate '$msg'`; | |
last unless $result; | |
} | |
$msg = `sudo /etc/init.d/ntp start`; | |
`logger -- $0 ntp start '$msg'`; | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment