NTP Monitor
Problem this snippet solves:
Version 9 (tested on v9.2.4)
Based on F5's example monitor, with the NTP check added. We make sure that the node gives us an NTP response and that the node hasn't become stratum 16 (ie, it's lost it's source). We use the CPAN Net::NTP module to make things easy.
Just use it like a normal external monitor, it only uses the default IP and port.
Code :
#!/usr/bin/perl -w ############################################################################### # # # F5 Networks and BIG/ip(c) Copyright # # # # No part of the software may be reproduced or transmitted in any form or by # # any means, electronic or mechanical, for any purpose, without express # # written permission of F5 Networks, Inc. It is against the law to copy the # # software. No part of this program may be reproduced or transmitted in any # # form or by any means, electronic or mechanical, including photocopying, # # recording, or information storage and retrieval systems, for any purpose # # other than the purchasers personal use, without the express written # # permission of F5 Networks, Inc. Copyright (c) 1996-2005 BIG/ip Software. All # # rights reserved. Our services are only available for legal users of the # # program for instance in case we extend our services by offering updating of # # files through Internet. # # # ############################################################################### # # # As for any external monitor program, the first two command # line arguments are the node ip address and the node port. # After that its whatever is supplied via the monitor template. # # Caveat: This does assume that you're using IPv4. # use lib "/shared/lib/perl5"; use strict; use Net::NTP; require 5.005; # Derive and untaint programname. my $programname = '/' . $0; $programname =~ m/^.*\/([^\/]+)$/; $programname = $1; if ($programname eq '') { die "Bad data in program name\n" } # Process ID and file where it's to be stored. The format # is significant. my $node = $ARGV[0]; $node =~ s/^::ffff://; my $port = $ARGV[1]; my $pidfile = "/var/run/$programname.$node..$port.pid"; my $pid = "$$"; # Maintenence. Clean up any existing EAV. if (-f $pidfile ) { open(PID, "<$pidfile"); my $pid =; close(PID); if ( $pid ) { chomp $pid; $pid =~ m/^(\d+)$/; $pid = $1; if ( $pid ) { kill 9, $pid; } } unlink($pidfile); } # Create a new maintenence file. open(PID, ">$pidfile"); print PID $pid, "\n"; close(PID); ########################################3 ## if (try_ntp_test($node,$port)) { print "OK\n"; } unlink($pidfile); exit(0); ######## sub try_ntp_test { # we just make sure we get a response # and that the server isn't a stratum # 16 server (ie, it's lost it's time source). my ($node,$port) = @_; my %response; eval { %response = get_ntp_response($node,$port); }; if ($@) { return 0; } else { if ($response{'Stratum'} =~ /\d+/) { # if the stratum is a number if ($response{'Stratum'} == 16) { return 0; } else { # and it isn't 16 return 1; } } else { return 0; } } }
Tested this on version:
11.0- WeaverJKNimbostratus
Thanks, Mark, for the background info.
If you don't mind, let's just walk through the steps again...
Should this work: ?
SSH or Console to the F5. Navigate to /shared/lib. Create a directory called "perl5" with 755 permissions. (Note: I created the directory and allowed it to inherit permissions). TFTP the NTP.pm file (from the ntp.zip file from the other post) to /shared/lib/perl5/Net/NTP.pm and set the permissions to 755. Copy the text above and paste it into a notepad.exe text file on a Windows computer. Use that Windows computer to connect to the Configuration Utility (CU). Use CU. Go to System > File Management > External Monitor File List (or something close). Import the contents of the text file while providing the external monitor a name.
Edit the external monitor to verify that it does not contain invalid characters (such as the question mark inside the diamond). Create a Monitor. Define the type as External. Select the External Monitor. Assign the monitor to a Pool. Pool Members are Nodes that are NTP servers.
Did I miss something or should this work?
Thanks!
John
- Mark_57945Nimbostratus
External monitor input handling changed between version 10 and version 11. In version 10 and earlier, they used environment variables to pass the IP and port. Starting in version 11, the IP and port are passed as argv[0] and argv[1].
I don't know what to tell you about the script not working for you. The script above is what I currently have in service.
- WeaverJKNimbostratus
The script above uses arguments instead of environment variables.
Script hasn't worked with or without the invalid characters mentioned above.
Thanks for any additional input.
- WeaverJKNimbostratus
Great point, Mark. I believe I addressed that question in my initial post, which DevCentral trashed as I was not logged in at the time. I had to retype the post and left out the bit about the NTP services functioning.
As a temporary measure, when I first configured the monitor, I set up a monitor to check port 123. The Nodes were all Active. The Printers which are using the VS/VIP received their NTP configurations without a problem.
The issue is when I remove the "MON_NTP_123" monitor and replace it with the "MON_EXT_NTP" monitor.
Other systems using the Nodes directly (not going through the VS/VIP/F5) are also obtaining time synchronization appropriately.
I can try deleting and importing the monitor file again, without modifying it, but I truly would expect the program to fail if it contained characters that the F5 was not happy with. Not to say that the code on this page is that way, but with the copying and pasting I had to do on a Mac OS, who knows what characters were thrown into the mix. ;)
- Mark_57945Nimbostratus
'use lib "/shared/lib/perl5";' is correct, so leaving it as-is was the right thing to do.
First thing I would do is make sure that your pool config is correct and that your NTP servers really are up and configured correctly. (e.g. responding to remote queries, not stratum 16). I don't know where those invalid characters came from when you downloaded it, everything looks OK when I look at the code on this page. I suspect that you may have broken the code when you deleted the invalid character markers.
- WeaverJKNimbostratus
Mark, thanks for your input.
Mark, thank you for explaining the Net::NTP section. I Googled it earlier but did not make the connection to the file structure as you explained it. I have no experience with "perl" at this time.
I changed the actual directory structure as suggested -> /shared/lib/perl5/Net/NTP.pm. I left the "use lib" statement as per the code in this article (use lib "/shared/lib/perl5";). I used the Configuration Utility to examine the external monitor. I discovered about six instances of invalid characters (was a question mark inside a black diamond). I removed these characters.
Tried the monitor again and the members went to red diamond down.
Any other thoughts? Thanks!
- Mark_57945Nimbostratus
If I read what you did correctly, you created /shared/lib/perl5/NTP.pm. Unfortunately, that isn't how Perl manages it's modules. The way Perl typically stores/accesses it's module files, the :: is translated into a file system directory break.
So, for Net::NTP above, stored in /shared/lib/perl5, the full path to NTP.pm that Perl expects would be /shared/lib/perl5/Net/NTP.pm.
- WeaverJKNimbostratus
Thanks to philh, Mark S., Rao, and Mark for their contributions.
 
Looking for assistance determining where my use of the above code may have gone wrong.
 
Steps taken:
 
A) Within /shared/lib, created "perl5" directory with default permissions.
 
B) Per this page: https://devcentral.f5.com/s/articles/ntp-monitor-for-11x-with-complete-instructions-999 Downloaded and extracted ntp.zip contents. TFTPed NTP.pm to /shared/lib/perl5 and saved it with 755 permissions.
 
C) Used the code above in a file named "ntp_mon."
 
D) Used the F5 File Management External Monitors section to upload "ntp_mon" as "MON_EXT_NTP."
 
E) Created a Monitor called "MON_NTP" that used "MON_EXT_NTP" as an external monitor.
 
F) Modified the Pool to use the "MON_NTP" monitor.
 
Results: Pool Members showed as red diamond down.
 
I did not use Arguments or Variables when creating the external monitor configuration as neither article mentioned the configuration of arguments or variables.
 
I just re-re-read one of the articles and noticed that it uses only the "default" IP and Port. I wonder what the author means by this. I presumed that the monitor would send an NTP request to the IP address of the Member over its IP and Port. I also assumed that the BIG-IP would be intelligent enough to use a static or floating self IP on the same subnet as Member in order to attempt to perform the NTP query.
 
Thanks for your input,
 
John
 
- Mark_57945Nimbostratus
I updated the code block on this page to include the monitor here, rather than needing to follow the link to the old location.
I included Rao's changes to make the monitor compatible with v11 and later. Rather than "$node = substr $node,7;;", I did "$node =~ s/^::ffff://;" to hopefully not break v6 node addresses. (I don't have any v6 to test, but Rao's use use of substr was sure to break them)
I also moved Net::NTP from /usr/bin/monitors/CPAN to /shared/lib/perl5 because I don't want the monitor to break when I upgrade Big IP.
- Godfrey_BennettNimbostratus
Rao, I don't quite understand your suggestion for modification - would it be possible to modify the source file to show exactly what needs to be done? I am interested in testing this on v12.x, which I think should be very close to v11. Thanks