Monitoring NTP servers effectively can often be challenging. If you're using NetScaler, custom Perl-based monitors can provide a neat solution. Today I'll share a straightforward Perl script you can deploy to monitor your NTP server's stratum level.
Why monitor NTP Stratum?
NTP Stratum indicates how many hops away an NTP server is from a primary time source. Lower values (1-15) are reliable, while a stratum of 16 usually means the server is unsynchronized or unreachable. Monitoring this helps ensure accurate time synchronization across your infrastructure.
How the Script Works
This simple script automatically checks the NTP service running on the monitored server (using its service IP directly) and verifies the server’s stratum level using ntpdate in query-only mode (ntpdate -q).
Here's the core logic:
- Retrieve Service IP Automatically: The script pulls the service IP directly from the NetScaler service.
- Run NTP Query: It uses Perl's backtick operator to execute the ntpdate command to query the server.
- Parse Output: The script extracts the stratum number from the command output.
-
Evaluate Response:
- If the stratum is between 1 and 15, it means the NTP server is healthy, and the script reports success.
- If the stratum is 16, the server is unsynchronized or unreachable, so it reports failure.
- Any other unexpected output also results in a failure notification.
Deploying the Script
Save this Perl script below in your NetScaler's /nsconfig/monitors/ directory.
Provide the proper permissions to execute the Script from NetScaler Shell with the following command:
chmod +x /netscaler/monitors/stratum.pl
Script (save as stratum.pl):
#!/usr/bin/perl -w
################################################################
## NTP Stratum Check Monitor for NetScaler v2.0
## Checks if the NTP server is alive by verifying its stratum level
## This version uses the service IP (first argument) automatically.
################################################################
use strict;
use Netscaler::KAS;
sub ntp_probe {
# Expect at least one argument (the service IP)
if (scalar(@_) < 1) {
return (1, "Insufficient number of arguments");
}
# Use the service IP (first argument) as the NTP server address
my $ntp_server = $_[0];
# Validate input
if (!defined $ntp_server || $ntp_server eq "") {
return (1, "Error: NTP server not specified");
}
# Command to query the NTP server (using ntpdate in query-only mode)
my $cmd = "/usr/sbin/ntpdate -q $ntp_server 2>&1";
my $output = `$cmd`;
my $exit_code = $? >> 8; # Extract the actual exit code
# Check if the command executed successfully
if ($exit_code != 0) {
return (1, "Error: ntpdate failed - $output");
}
# Parse the output for the stratum level
if ($output =~ /stratum (\d+)/) {
my $stratum = $1;
# If the stratum is 16, the server is unsynchronized or unreachable
if ($stratum == 16) {
return (1, "NTP server $ntp_server is unreachable or unsynchronized, stratum $stratum");
}
# For a valid stratum (1-15), return success without a message
elsif ($stratum >= 1 && $stratum <= 15) {
return 0;
}
else {
return (1, "Unexpected stratum level $stratum from NTP server $ntp_server");
}
}
else {
return (1, "Error: Could not determine stratum from output - $output");
}
}
# Register the probe subroutine with the KAS module
probe(\&ntp_probe);
NetScaler CLI Commands
Use the commands below to create the service in the NetScaler CLI:
#Create a NetScaler Service
add service NTP_SERVICE <NTP SERVER IP> UDP 123 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport NO -sp OFF -cltTimeout 120 -svrTimeout 120 -CKA NO -TCPB NO -CMP NO
#Create a custom monitor
add lb monitor ntp-stratum-monitor USER -scriptName stratum.pl -dispatcherIP 127.0.0.1 -dispatcherPort 3013 -LRTM DISABLED -interval 10 -resptimeout 5
#Bind the Monitor to the service
bind service NTP_SERVICE -monitorName ntp-stratum-monitor
Final Thoughts
This lightweight script simplifies NTP monitoring so the NetScaler monitor reflects the actual state of the NTP Servers. Try it out!
Disclaimer
The above mentioned sample code is provided to you as is with no representations, warranties or conditions of any kind. You may use, modify and distribute it at your own risk. CLOUD SOFTWARE GROUP DISCLAIMS ALL WARRANTIES WHATSOEVER, EXPRESS, IMPLIED, WRITTEN, ORAL OR STATUTORY, INCLUDING WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NONINFRINGEMENT. Without limiting the generality of the foregoing, you acknowledge and agree that (a) the sample code may exhibit errors, design flaws or other problems, possibly resulting in loss of data or damage to property; (b) it may not be possible to make the sample code fully functional; and © CLOUD SOFTWARE GROUP may, without notice or liability to you, cease to make available the current version and/or any future versions of the sample code. In no event should the code be used to support ultra-hazardous activities, including but not limited to life support or blasting activities. NEITHER CLOUD SOFTWARE GROUP NOR ITS AFFILIATES OR AGENTS WILL BE LIABLE, UNDER BREACH OF CONTRACT OR ANY OTHER THEORY OF LIABILITY, FOR ANY DAMAGES WHATSOEVER ARISING FROM USE OF THE SAMPLE CODE, INCLUDING WITHOUT LIMITATION DIRECT, SPECIAL, INCIDENTAL, PUNITIVE, CONSEQUENTIAL OR OTHER DAMAGES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Although the copyright in the code belongs to CLOUD SOFTWARE GROUP, any distribution of the sample code should include only your own standard copyright attribution, and not that of CLOUD SOFTWARE GROUP. You agree to indemnify and defend CLOUD SOFTWARE GROUP against any and all claims arising from your use, modification or distribution of the sample code.
Recommended Comments
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.