monitor
37 TopicsExternal SMTP monitor (written in Go)
Problem this snippet solves: We wrote an external SMTP monitor to work around K99840695. It moderatly customizable, supports STARTTLS and has builtin support to test content filtering via EICAR/GTUBE. The code is on Github, auto-generated releases are on the project's [https://github.com/hreese/f5-smtp-monitor/releases](release page). Code : https://github.com/hreese/f5-smtp-monitor Tested this on version: 11.6342Views0likes0CommentsTACACS+ External Monitor (Python)
Problem this snippet solves: This script is an external monitor for TACACS+ that simulates a TACACS+ client authenticating a test user, and marks the status of a pool member as up if the authentication is successful. If the connection is down/times out, or the authentication fails due to invalid account settings, the script marks the pool member status as down. This is heavily inspired by the Radius External Monitor (Python) by AlanTen. How to use this snippet: Prerequisite This script uses the TACACS+ Python client by Ansible (tested on version 2.6). Create the directory /config/eav/tacacs_plus on BIG-IP Copy all contents from tacacs_plus package into /config/eav/tacacs_plus. You may also need to download six.py from https://raw.githubusercontent.com/benjaminp/six/master/six.py and place it in /config/eav/tacacs_plus. You will need to have a test account provisioned on the TACACS+ server for the script to perform authentication. Installation On BIG-IP, import the code snippet below as an External Monitor Program File. Monitor Configuration Set up an External monitor with the imported file, and configure it with the following environment variables: KEY: TACACS+serversecret USER: Usernamefortestaccount PASSWORD: Passwordfortestaccount MOD_PATH: PathtolocationofPythonpackagetacacs_plus,default:/config/eav TIMEOUT: DurationtowaitforconnectivitytoTACACSservertobeestablished,default:3 Troubleshooting SSH to BIG-IP and run the script locally $ cd /config/filestore/files_d/Common_d/external_monitor_d/ # Get name of uploaded file, e.g.: $ ls -la ... -rwxr-xr-x. 1 tomcat tomcat 1883 2021-09-17 04:05 :Common:tacacs-monitor_39568_7 # Run the script with the corresponding variables $ KEY=<my_tacacs_key> USER=<testuser> PASSWORD=<supersecure> python <external program file, e.g.:Common:tacacs-monitor_39568_7> <TACACS+ server IP> <TACACS+ server port> Code : #!/usr/bin/env python # # Filename : tacacs_plus_mon.py # Author : Leon Seng # Version : 1.2 # Date : 2021/09/21 # Python ver: 2.6+ # F5 version: 12.1+ # # ========== Installation # Import this script via GUI: # System > File Management > External Monitor Program File List > Import... # Name it however you want. # Get, modify and copy the following modules: # ========== Required modules # -- six -- # https://pypi.org/project/six/ # Copy six.py into /config/eav # # -- tacacs_plus -- # https://pypi.org/project/tacacs_plus/ | https://github.com/ansible/tacacs_plus # Copy tacacs_plus directory into /config/eav # ========== Environment Variables # NODE_IP - Supplied by F5 monitor as first argument # NODE_PORT - Supplied by F5 monitor as second argument # KEY - TACACS+ server secret # USER - Username for test account # PASSWORD - Password for test account # MOD_PATH - Path to location of Python package tacacs_plus, default: /config/eav # TIMEOUT - Duration to wait for connectivity to TACACS server to be established, default: 3 import os import socket import sys if os.environ.get('MOD_PATH'): sys.path.append(os.environ.get('MOD_PATH')) else: sys.path.append('/config/eav') # https://github.com/ansible/tacacs_plus from tacacs_plus.client import TACACSClient node_ip = sys.argv[1] node_port = int(sys.argv[2]) key = os.environ.get("KEY") user = os.environ.get("USER") password = os.environ.get("PASSWORD") timeout = int(os.environ.get("TIMEOUT", 3)) # Determine if node IP is IPv4 or IPv6 family = None try: socket.inet_pton(socket.AF_INET, node_ip) family = socket.AF_INET except socket.error: # not a valid address try: socket.inet_pton(socket.AF_INET6, node_ip) family = socket.AF_INET6 except socket.error: sys.exit(1) # Authenticate against TACACS server client = TACACSClient(node_ip, node_port, key, timeout=timeout, family=family) try: auth = client.authenticate(user, password) if auth.valid: print "up" except socket.error: # EAV script marks node as DOWN when no output is present pass Tested this on version: 12.11.2KViews1like0CommentsHTTP Monitor cURL Basic GET
Problem this snippet solves: External HTTP monitor script that requests a URI from the pool member to which it is applied, marking it up if the expected response is received. URI and response string are user-configurable. cURL by default uses HTTP/1.1 and, since no hostname is specified in the cURL command, inserts the IP address in the Host header. NOTE: Use external monitors only when a built-in monitor won't do the trick. This example is intended to demonstrate the basic use of cURL (which offers a large number of other useful options) in an external monitor. However, if you don't need those extra options, a very simple HTTP monitor such as this is much more efficiently configured using the built-in HTTP monitor template instead. How to use this snippet: Create a new file containing the code below in /usr/bin/monitors on the LTM filesystem. Permissions on the file must be 700 or better, giving root rwx access to the file. 2. Create a monitor profile of type "External" with the following values: External Program: . . the name of the script file created in step 1 Variables: Name.......Value URI . . . . .the URI to request from the server RECV . . . . the expected response Adjust the interval and timeout as appropriate for your application. Jan 3 00:00:00 local/bigip err logger: EAV exceeded runtime needed to kill 10.0.0.10:80 If the interval and timeout is smaller then the execution time of the script, the monitor marks the element down and logs a message in /var/log/ltm. This is a false negative. To fix this, please increase the interval and timeout accordingly. Code : #!/bin/sh # # (c) Copyright 1996-2007 F5 Networks, Inc. # # This software is confidential and may contain trade secrets that are the # property of F5 Networks, Inc. No part of the software may be disclosed # to other parties without the express written consent of F5 Networks, Inc. # It is against the law to copy the software. No part of the software may # be reproduced, transmitted, or distributed in any form or by any means, # electronic or mechanical, including photocopying, recording, or information # storage and retrieval systems, for any purpose without the express written # permission of F5 Networks, Inc. Our services are only available for legal # users of the program, for instance in the event that we extend our services # by offering the updating of files via the Internet. # # @(#) $Id: http_monitor_cURL+GET,v 1.0 2007/06/28 16:10:15 deb Exp $ # (based on sample_monitor,v 1.3 2005/02/04 18:47:17 saxon) # # these arguments supplied automatically for all external monitors: # $1 = IP (IPv6 notation. IPv4 addresses are passed in the form # ::ffff:w.x.y.z # where "w.x.y.z" is the IPv4 address) # $2 = port (decimal, host byte order) # # Additional command line arguments ($3 and higher) may be specified in the monitor template # This example does not expect any additional command line arguments # # Name/Value pairs may also be specified in the monitor template # This example expects the following Name/Vaule pairs: # URI = the URI to request from the server # RECV = the expected response (not case sensitive) # # remove IPv6/IPv4 compatibility prefix (LTM passes addresses in IPv6 format) IP=`echo ${1} | sed 's/::ffff://'` PORT=${2} PIDFILE="/var/run/`basename ${0}`.${IP}_${PORT}.pid" # kill of the last instance of this monitor if hung and log current pid if [ -f $PIDFILE ] then echo "EAV exceeded runtime needed to kill ${IP}:${PORT}" | logger -p local0.error kill -9 `cat $PIDFILE` > /dev/null 2>&1 fi echo "$$" > $PIDFILE # send request & check for expected response curl -fNs http://${IP}:${PORT}${URI} | grep -i "${RECV}" 2>&1 > /dev/null # mark node UP if expected response was received if [ $? -eq 0 ] then rm -f $PIDFILE echo "UP" else rm -f $PIDFILE fi exit4.7KViews0likes6CommentsMonitor SNMP OID result check
Problem this snippet solves: The purpose of this monitor is to check for the value of an SNMP OID and mark the server up if it equals the result variable which is customizable. Copy the monitor text below to a new file called snmp-check and move that file to the /usr/bin/monitors folder in BIG-IP. Make it executable by typing “chmod 755 snmp-check” Create a new monitor of type External. Set the Interval and Timeouts desired. Define the location of the file. Add 3 variables, one with Name “OID” (case-sensitive) which contains the OID you wish to poll. Add the next with Name “community” which contains the community string. The last with the Name “result” which contains the value you are looking for. In the Configuration Drop-down box, select Advanced and then under the Alias Service Port, select SNMP or type in the customer SNMP port number. Code : # (file not fixed yet)420Views0likes1CommentInterface Failsafe Monitor
Problem this snippet solves: Another slick solution for a couple of common requirement in high performance environments: To fail over immediately when a physical network connection fails connectivity, or if the number of active members in a trunk falls below the configured minimum. The first sample supports individual interface monitoring. The second supports the more complex trunk management. How to use this snippet: http://devcentral.f5.com/Default.aspx?tabid=63&articleType=ArticleView&articleId=166 Monitor Source: Interface Failsafe only #!/bin/bash # (c) Copyright 2007 F5 Networks, Inc. # Kirk Bauer # Pass in each interface to monitor via the Arguments field in the GUI # Collect arguments (first remove IP and port as we don't use those) shift shift interfaces="$*" b interface show > /tmp/b_interface_show for i in $interfaces ; do status=`grep "^ *$i " /tmp/b_interface_show | awk '{print $2}'` if [ "$status" != "UP" ] ; then logger -p local0.notice "$MON_TMPL_NAME: interface $i is not up (status: $status)" exit 1 fi done # All specified interfaces are up... echo "up" exit 0 Monitor Source: Interface Failsafe w/Trunk Minumum Active Members support Code : #!/bin/bash # (c) Copyright 2007 F5 Networks, Inc. # Kirk Bauer # Pass in each interface to monitor via the Arguments field in the GUI. # Each interface may be one of the following: # Physical interface (1.1, 1.2, etc) # Name of a trunk (if at least one interface is up the trunk is considered up) # trunk=min where trunk is the name of the trunk and min is the minimum number # of physical interfaces in the trunk that must be up # For example, the following arguments will make sure that the 1.1 interface is # up and test_trunk has at least two interfaces in it that are up: # 1.1 test_trunk=2 # To test on command-line, use fillers for first two arguments: # /usr/bin/monitors/interface_monitor.sh X X 1.1 1.2 1.3 ... # Collect arguments (first remove IP and port as we don't use those) shift shift interfaces="$*" b interface show > /tmp/b_interface_show for i in $interfaces ; do if grep -q "^ *$i " /tmp/b_interface_show ; then # Physical Interface status=`grep "^ *$i " /tmp/b_interface_show | awk '{print $2}'` if [ "$status" != "UP" ] ; then logger -p local0.notice "$MON_TMPL_NAME: interface $i is not up (status: $status)" exit 1 fi else # Not a physical interface, assume a trunked interface trunk="$i" reqcount=1 if echo "$trunk" | grep -q '=' ; then trunk="$(echo "$i" | sed 's/=.*//')" reqcount="$(echo "$i" | sed 's/^.*=//')" fi upcount=0 for status in `grep "$trunk" /tmp/b_interface_show | awk '{print $2}'` ; do [ "$status" == "UP" ] && upcount=$[$upcount+1] done if [ $upcount -lt $reqcount ] ; then logger -p local0.notice "$MON_TMPL_NAME: trunk $trunk is down (has only $upcount active interfaces, $reqcount required)" exit 1 fi fi done # All specified interfaces are up... echo "up" exit 0327Views0likes4CommentsF5 StoreFront XML Broker Monitor
Problem this snippet solves: I successfully was able to manually build a monitor outside of the iApp for Citrix Storefront deployment, that is a little more complex than the original one. How to use this snippet: Just copy and past this into your send string for your monitor. There are a few things that will have to be adjusted, such as the host, the username, and password, and content-length. To find the proper content length, plug in your information that is necessary. Then take the characters between the '<?xml version' and '</NFuseProtocol>' and past them into a text editor. Remove all escape characters such as "\". Highlight the string and if your text editor has the option, it will show you the character count that you selected. This is your new content-length. If the code is executed correctly you will see a list of published Apps, such as Notepad. If you wanted to have a monitor that didn't pass the username and password in clear text, you will need to do so in an external monitor. In my use case, the user permissions were locked down just enough to make the monitor work and that is all. Code : POST /scripts/wpnbr.dll HTTP/1.1\r\nContent-Length: 492\r\nContent-Type: text/xml\r\nConnection: close\r\nHost: hostname\r\n\r\n permissions all ica30 content user password domain Tested this on version: 13.0468Views3likes0Commentssnmp-check external monitor
Problem this snippet solves: This external monitor script runs an snmpget to pool members and marks the members up or down based upon the result. Specifically created for this GTM/APM use case, but can be modified as needed. How to use this snippet: copy the contents of this file into /config/monitors/snmp-check, and then in the external monitor configuration, reference the monitor and provide the following variable key/value pairs: result=<result> community=<community> OID=<oid> Code : #!/bin/sh # # (c) Copyright 1996-2005 F5 Networks, Inc. # # This software is confidential and may contain trade secrets that are the # property of F5 Networks, Inc. No part of the software may be disclosed # to other parties without the express written consent of F5 Networks, Inc. # It is against the law to copy the software. No part of the software may # be reproduced, transmitted, or distributed in any form or by any means, # electronic or mechanical, including photocopying, recording, or information # storage and retrieval systems, for any purpose without the express written # permission of F5 Networks, Inc. Our services are only available for legal # users of the program, for instance in the event that we extend our services # by offering the updating of files via the Internet. # # @(#) $Id: sample_monitor,v 1.3 2005/02/04 18:47:17 saxon Exp $ # # # these arguments supplied automatically for all external pingers: # $1 = IP (nnn.nnn.nnn.nnn notation or hostname) # $2 = port (decimal, host byte order) # $3 and higher = additional arguments # # $MONITOR_NAME = name of the monitor # # In this sample script, $3 is the regular expression # #These lines are required to control the process ID of the monitor pidfile="/var/run/$MONITOR_NAME.$1..$2.pid" if [ -f $pidfile ] then kill -9 `cat $pidfile` > /dev/null 2>&1 fi echo "$$" > $pidfile #Since version9 uses the ipv6 native version of the IP address, parse that down #for usage node_ip=`echo $1 | sed 's/::ffff://'` #Log the variables for debugging #echo IP= $node_ip Port =$2 OID= $OID comm= $community result= $result >> /var/tmp/test #Create a variable called answer that contains the result of the snmpwalk. answer=`snmpget $node_ip -c $community -O v $OID | awk '{print $2}'` #Log the answer for debugging #echo Answer= $answer >> /var/tmp/test if [ $answer -lt $result ] then echo "up" fi rm -f $pidfile Tested this on version: No Version Found1.9KViews2likes5CommentsHTTPS SNI Monitor
Problem this snippet solves: Hi, You may or may not already have encountered a webserver that requires the SNI (Server Name Indication) extension in order to know which website it needs to serve you. It comes down to "if you don't tell me what you want, I'll give you a default website or even simply reset the connection". A typical IIS8.5 will do this, even with the 'Require SNI' checkbox unchecked. So you have your F5, with its HTTPS monitors. Those monitors do not yet support SNI, as they have no means of specifying the hostname you want to use for SNI. In comes a litle script, that will do exactly that. Here's a few quick steps to get you started: Download the script from this article (it's posted on pastebin: http://pastebin.com/hQWnkbMg, listed below and added as attachment). Import it under 'System' > 'File Management' > 'External Monitor Program File List'. Create a monitor of type 'External' and select the script from the picklist under 'External Program'. Add your specific variables (explanation below). Add the monitor to a pool and you are good to go. A quick explanation of the variables: METHOD (GET, POST, HEAD, OPTIONS, etc. - defaults to 'GET') URI ("the part after the hostname" - defaults to '/') HTTPSTATUS (the status code you want to receive from the server - defaults to '200') HOSTNAME (the hostname to be used for SNI and the Host Header - defaults to the IP of the node being targetted) TARGETIP and TARGETPORT (same functionality as the 'alias' fields in the original monitors - defaults to the IP of the node being targetted and port 443) DEBUG (set to 0 for nothing, set to 1 for logs in /var/log/ltm - defaults to '0') RECEIVESTRING (the string that needs to be present in the server response - default is empty, so not checked) HEADERX (replace the X by a number between 1 and 50, the value for this is a valid HTTP header line, i.e. "User-Agent: Mozilla" - no defaults) EXITSTATUS (set to 0 to make the monitor always mark te pool members as up; it's fairly useless, but hey... - defaults to 1) There is a small thing you need to know though: due to the nature of the openssl binary (more specifically the sclient), we are presented with a "stdin redirection problem". The bottom line is that your F5 cannot be "slow" and by slow I mean that if it requires more than 3 seconds to pipe a string into openssl sclient, the script will always fail. This limit is defined in the variable "monitorstdinsleeptime" and defaults to '3'. You can set it to something else by adding a variable named 'STDINSLEEPTIME' and giving it a value. From my experience, anything above 3 stalls the "F5 script executer", anything below 2 is too fast for openssl to read the request from stdin, effectively sending nothing and thus yielding 'down'. When you enable debugging (DEBUG=1), you can see what I mean for yourself: no more log entries for the script when STDINSLEEPTIME is set too high; always down when you set it too low. Kind regards, Thomas Schockaert Code : #!/bin/bash ##### Sanity checks ## Strictly IPv4 notation. # The openssl binary doesn't allow the use of IPv6 notation in the -connect parameter of the s_client subcommand. # F5 exports the NODE_IP variable, which always contains the IPv6-form, even when the IP address is IPv4. # Stripping the unwanted part solves this. monitor_targetip=$(echo "$1" | sed 's/::ffff://') ## ## Binary validation # Finding all the binaries is paramount for this script to run successfully. These binaries must be found under one or more directories in the PATH variable. # You can modify the PATH variable under which the monitor executes by explicitly defining it in the Variables section of the monitor definition. required_programs="openssl logger cat grep egrep awk tr seq sleep" missing_programs=0 missing_programs_output="" missing_programs_counter=0 for current_program in $required_programs ; do program_path=$(which $current_program) if [ $? -eq 0 ] ; then eval "$current_program=$program_path" else output="$missing_programs_output$current_program," let missing_programs_counter=$missing_programs_counter+1 fi done if [ $missing_programs_counter -gt 0 ] ; then echo -e "ERROR: An external monitor script failed to locate one or more of its required programs. The script cannot continue unless you fix this." >> /var/log/ltm echo -e "The program(s) that could not be found are: $missing_programs_output" >> /var/log/ltm echo -e "The location of these programs needs to be under one the following directories: '$PATH'" >> /var/log/ltm exit 1 fi ## ##### ##### Preparations before running the checks ## Setting the default settings # These are needed in case the creator of the monitor failed to specify all the required variables monitor_debug=0 monitor_method="GET" monitor_uri="/" monitor_httpstatus="200" monitor_hostname="$monitor_targetip" monitor_targetport="$NODE_PORT" monitor_receivestring="" monitor_header="" monitor_stdin_sleeptime="3" # this is required to make openssl s_client accept the input from stdin before it closes. monitor_exitstatus=1 log_monitor_debug_specified=0 log_monitor_method_specified=0 log_monitor_uri_specified=0 log_monitor_httpstatus_specified=0 log_monitor_hostname_specified=0 log_monitor_targetport_specified=0 log_monitor_receivestring_specified=0 log_monitor_header_specified=0 log_monitor_receivestring_match=0 log_monitor_httpstatus_match=0 ## ## Overriding the default settings if needed # This part loops through the possible variables and checks if they have been defined. # If one has been defined, it checks if it's not empty and adds it to the actual action-variable ($monitor_something). monitor_variable_items="method uri httpstatus hostname targetip targetport debug receivestring header stdin_sleeptime exitstatus" for current_monitor_variable_item in $monitor_variable_items ; do current_monitor_variable_name_for_usage="monitor_${current_monitor_variable_item}" current_monitor_variable_name_for_logging="log_${current_monitor_variable_name_for_usage}_specified" if [ "$current_monitor_variable_item" == "header" ] ; then tmp="" for i in `$seq 1 50` ; do current_monitor_variable_name_for_input="$(echo "$current_monitor_variable_item" | $tr 'a-z' 'A-Z')$i" eval "current_monitor_variable_value_for_input=\$$current_monitor_variable_name_for_input" if ! [ "$current_monitor_variable_value_for_input" == "" ] ; then if [ $i -eq 1 ] ; then tmp="${current_monitor_variable_value_for_input}" else tmp="${tmp}\r\n${current_monitor_variable_value_for_input}" fi fi unset current_monitor_variable_name_for_input done eval "$current_monitor_variable_name_for_usage=\"$tmp\"" eval "$current_monitor_variable_name_for_logging=1" else current_monitor_variable_name_for_input=$(echo "$current_monitor_variable_item" | tr 'a-z' 'A-Z') eval "current_monitor_variable_value_for_input=\$$current_monitor_variable_name_for_input" eval "current_monitor_variable_value_for_usage=\$$current_monitor_variable_name_for_usage" if ! [ "$current_monitor_variable_value_for_input" == "" ] ; then eval "$current_monitor_variable_name_for_usage=$current_monitor_variable_value_for_input" eval "$current_monitor_variable_name_for_logging=1" fi fi unset tmp current_monitor_variable_name_for_usage current_monitor_variable_name_for_logging current_monitor_variable_name_for_input done ### ##### ##### Running the checks ## Obtaining the HTTP content through openssl http_content=`(echo -e "$monitor_method $monitor_uri HTTP/1.1\r\nHost: $monitor_hostname\r\n${monitor_header}\r"; $sleep $monitor_stdin_sleeptime) | $openssl s_client -connect $monitor_targetip:$monitor_targetport -servername $monitor_hostname` ## ## Obtaining the HTTP Status code from the returned contents http_error_code=$(echo "$http_content" | $egrep "HTTP/1\.[0-1] " | $awk '{print $2}') ## ## Determining the 'up' or 'down' status if [ "$http_error_code" == "$monitor_httpstatus" ] ; then log_monitor_httpstatus_match=1 if ! [ "$monitor_receivestring" == "" ] ; then receive_string_check=$(echo "$http_content" | $grep "$monitor_receivestring") if ! [ "$receive_string_check" == "" ] ; then log_monitor_receivestring_match=1 monitor_exitstatus=0 fi else monitor_exitstatus=0 fi fi ## ##### ##### Supplying the debug logs if requested ## Dump each variable if [ "$monitor_debug" == "1" ] ; then this_run=$(date +%s) log_prefix="HTTPS_SNI [$this_run]:" echo "" | $logger -p local0.debug echo "$log_prefix Monitor Description:" | $logger -p local0.debug for current_monitor_variable_item in $monitor_variable_items ; do current_monitor_variable_name_for_usage="monitor_${current_monitor_variable_item}" current_monitor_variable_name_for_logging="log_${current_monitor_variable_name_for_usage}_specified" eval "current_monitor_variable_value_for_usage=\"\$$current_monitor_variable_name_for_usage\"" eval "current_monitor_variable_value_for_logging=\$$current_monitor_variable_name_for_logging" if [ "$current_monitor_variable_value_for_logging" == "1" ] ; then echo "$log_prefix - $current_monitor_variable_name_for_usage => $current_monitor_variable_value_for_usage" | $logger -p local0.debug else echo "$log_prefix - $current_monitor_variable_name_for_usage => default ($current_monitor_variable_value_for_usage)" | $logger -p local0.debug fi unset current_monitor_variable_name_for_usage current_monitor_variable_name_for_logging done echo "$log_prefix Monitor Status:" | $logger -p local0.debug if [ "$log_monitor_receivestring_match" == "0" ] ; then echo "$log_prefix - Receive String: no match" | $logger -p local0.debug else echo "$log_prefix - Receive String: match" | $logger -p local0.debug fi if [ "$log_monitor_httpstatus_match" == "0" ] ; then echo "$log_prefix - HTTP Status: no match" | $logger -p local0.debug else echo "$log_prefix - Receive String: match" | $logger -p local0.debug fi if [ "$monitor_exitstatus" == "0" ] ; then echo "$log_prefix - Final Result: UP" | $logger -p local0.debug else echo "$log_prefix - Final Result: DOWN" | $logger -p local0.debug fi echo "" | logger -p local0.debug echo "" | logger -p local0.debug fi ## ##### ##### Telling F5 the monitor status should be up ## Echoing 'up' to stdout if [ "$monitor_exitstatus" == "0" ] ; then echo "up" fi ## ## Exiting accordingly (0 or 1) exit $monitor_exitstatus ## #####1.5KViews1like6CommentsNTP 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.01.5KViews0likes23CommentsDNS Monitor Using Dig
Problem this snippet solves: This monitor uses dig to verify an expected response from load balanced DNS servers. It accepts 2 command-line arguments: the name to be looked up, and a string found in the expected response. NOTE: Use external monitors only when a built-in monitor won't do the trick. This example is intended to demonstrate the basic use of dig in an external monitor to test UDP-based name services. How to use this snippet: Implementation Create a new file containing the code below on the LTM filesystem. Recommended location is /config/eav. Permissions on the file must be 700 or better, giving root rwx access to the file. 2. Create a monitor profile of type "External" with the following values: External Program: . . the name of the script file created in step 1 Arguments: * " ", where string has x.x.x.x format for A lookup and ::::::: format for AAAA lookups 3. Adjust the interval and timeout as appropriate for your application Alternative Monitor Uses dig(1) More Efficiently The Alternative Monitor Script below allows you to adjust dig(1) query type, timeout, and retry count. The dig(1) utility normally waits just 5 seconds for a response to each DNS query, and retries failed queries twice. 5 seconds is too short for many queries across the Internet. Suppose you have DNS servers using different Internet gateways and wish to load-balance client DNS queries (received on a virtual server address) to your DNS servers. You can monitor DNS server and Internet gateway availability at the same time by querying each DNS server for a short-TTL RR from somewhere out on the Internet (short TTL so local caching won't mask gateway failure). In this scenario (and in other cases not discussed here) you may wish to allow a longer dig(1) timeout and limit the number of retries. Some more implementation notes appear as comments in the script. #!/bin/bash # # Script 'dns-monitor' brought to you by COSTCO WHOLESALE CORP. # Prepared 2010-04-23 by Mark Seecof for Costco Wholesale Corp. # LTM gives every external-monitor program the target # node's IP address and port as arguments $1 $2 # We must strip off IPV6 notation node="${1#::ffff:}" port="${2}" # (To save time in the normal case we omit to validate # arguments, though it would not be difficult to do so.) # # When you setup your external monitor, give as 'arguments': # $3, the DNS name to query; # $4, the type of its RR (e.g., 'A'); # $5, a grep(1) pattern which will match a successful # (dig +short) result but not a failed one; # $6, the query timeout in seconds (at least 2 seconds less # than the monitor's overall timeout). # # $7 (optional) if you wish an unanswered query retried (only # needed with a lossy network or overloaded DNS server), give # the retry count as $7--and reduce your $6 query timeout # proportionally (i.e., if you double the number of queries, # cut query timeouts in half, because you must make the sum # of query timeouts less than the monitor's overall timeout). # # EXAMPLE MONITOR SETUP: # Suppose a working DNS server will respond within 10 seconds # maximum to queries for the following RR: #example.comNSns1.example.com # # Copy this script to /config/monitors/dns-monitor (on both # LTM's in a failover pair) and make executable (chmod +x). # For this example, we will check on the DNS server 3 times # per minute. Create an 'external' monitor, set 'external # program' to "/config/monitors/dns-monitor". Set 'interval' # to 20 seconds, 'timeout' to 15 seconds, and set 'arguments' # to "example.com NS ns1.example.com 10". The padding in the # various timeouts allows for variations in system load # affecting real response times. # # ('.' is a regex operator so the pattern "ns1.example.com" # is ambiguous-- but unlikely to cause trouble. If you will # never need to test mildly-variable query results, you may # change "grep -q" to "grep -q -F" below...) # query="${3}" type="${4}" want="${5}" timeout="${6:-5}" retry="${7:-0}" if /usr/bin/dig "@${node}" -p "${port}" +short \ -t "${type}" -q "${query}" "+time=${timeout}" \ "+retry=${retry}" | /bin/grep -q "${want}" 2>/dev/null ; then echo "UP" ; exit 0 ; fi exit 1 #bottom of file Code : #!/bin/sh # (c) Copyright 1996-2007 F5 Networks, Inc. # # This software is confidential and may contain trade secrets that are the # property of F5 Networks, Inc. No part of the software may be disclosed # to other parties without the express written consent of F5 Networks, Inc. # It is against the law to copy the software. No part of the software may # be reproduced, transmitted, or distributed in any form or by any means, # electronic or mechanical, including photocopying, recording, or information # storage and retrieval systems, for any purpose without the express written # permission of F5 Networks, Inc. Our services are only available for legal # users of the program, for instance in the event that we extend our services # by offering the updating of files via the Internet. # # # these arguments supplied automatically for all external monitors: # $1 = IP (nnn.nnn.nnn.nnn notation or hostname) # $2 = port (decimal, host byte order) -- not used in this monitor, assumes default port 53 # $3 = name to be looked up # $4 = string in expected response node_ip=`echo $1 | sed 's/::ffff://'` pidfile="/var/run/`basename $0`.$node_ip..$2.pid" if [ -f $pidfile ] then kill -9 `cat $pidfile` > /dev/null 2>&1 fi echo "$$" > $pidfile dig @${node_ip} ${3} | egrep -v '^$|^;' | grep ${4} > /dev/null 2>&1 # For AAAA lookups, use this instead # dig @${node_ip} ${3} AAAA| egrep -v '^$|^;' | grep ${4} > /dev/null 2>&1 status=$? if [ $status -eq 0 ] then rm -f $pidfile echo "UP" else rm -f $pidfile fi934Views0likes2Comments