78 lines
2.3 KiB
Ruby
78 lines
2.3 KiB
Ruby
require 'pp'
|
|
require 'socket'
|
|
require 'timeout'
|
|
|
|
Puppet::Parser::Functions::newfunction(:ntp_available, :doc => <<-EOS
|
|
The ntp_available function attempts to make an NTP request to a server or
|
|
servers and throws a puppet error if unable to make at least one successful
|
|
request. The ntp_available function takes a single parameter that can be one
|
|
of the following:
|
|
1) String - a single hostname
|
|
2) Array - an array of hostname strings
|
|
|
|
Examples:
|
|
ntp_available('pool.ntp.org')
|
|
ntp_available(['0.pool.ntp.org', '1.pool.ntp.org', '2.pool.ntp.org'])
|
|
EOS
|
|
) do |argv|
|
|
host = argv[0]
|
|
|
|
def ntp_query(host)
|
|
# time since unix epoch, RFC 868
|
|
time_offset = 2208988800
|
|
# timeout to wait for a response
|
|
timeout = 10
|
|
# an ntp packet
|
|
# http://blog.mattcrampton.com/post/88291892461/query-an-ntp-server-from-python
|
|
ntp_msg = "\x1b" + ("\0" * 47)
|
|
# our UDP socket
|
|
sock = UDPSocket.new
|
|
begin
|
|
# open up a socket to connect to the ntp host
|
|
sock.connect(host, 'ntp')
|
|
# send our ntp message to the ntp server
|
|
sock.print ntp_msg
|
|
sock.flush
|
|
# read the response
|
|
read, write, error = IO.select [sock], nil, nil, timeout
|
|
if read.nil?
|
|
# no response (timeout)
|
|
sock.close if sock
|
|
return false
|
|
else
|
|
data, _ = sock.recvfrom(960)
|
|
# un pack the response
|
|
# https://github.com/zencoder/net-ntp/blob/master/lib/net/ntp/ntp.rb#L194
|
|
parsed_data = data.unpack("a C3 n B16 n B16 H8 N B32 N B32 N B32 N B32")
|
|
# attempt to parse the time we got back
|
|
t = Time.at(parsed_data[13] - time_offset)
|
|
puts "Time from #{host} is #{t}"
|
|
end
|
|
sock.close if sock
|
|
rescue
|
|
sock.close if sock
|
|
return false
|
|
end
|
|
true
|
|
end
|
|
|
|
# our check boolean used to indicate we had at least one successful request
|
|
ok = false
|
|
# if passed an array, iterate throught he array and check each element
|
|
if host.instance_of? Array
|
|
host.each do |h|
|
|
if (ntp_query(h))
|
|
ok = true
|
|
end
|
|
end
|
|
else
|
|
ok = ntp_query(host)
|
|
end
|
|
# we need at least one successful request
|
|
if !ok
|
|
raise Puppet::Error, "ERROR: Unable to communicate with at least one of NTP server, checked the following host(s): #{host}"
|
|
end
|
|
return ok
|
|
end
|
|
# vim: set ts=2 sw=2 et :
|