HTTP Monitor cURL GET With Host Specific Headers

Problem this snippet solves:

External HTTP monitor script that requests a URI from the pool member to which it is applied, inserting the appropriate hostname in the Host header, and marking the pool member UP if the expected response is received. URI and response string are user-configurable. The Host header value will be inserted based on the IP-to-hostname mappings specified in the case construct in the monitor script. (If no match is found, the the IP address of the pool member is inserted 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 use of cURL (which offers a large number of other useful options) to insert variable headers in an external monitor. However, if nothing in the request varies, and don't need those extra options, more basic HTTP monitors are much more efficiently configured using the built-in HTTP monitor template instead.

UPDATE: The script below had a logic error in it where by it was using the NODE and PORT variables to create a PID file before the variables were defined. This meant that if your monitor took long enough to run the PID running monitor was killed before it finished and a new process ran in its place. This gave the appearence of the monitor not functioning correctly. I have corrected this below.

How to use this snippet:

  1. 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. Edit the "case" construct in the code to include the IP addresses and Host header values for each pool member to which this monitor will be applied.
  3. 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
  4. 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+HostSpecificHeaders,v 1.0 2007/06/28 15:03: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 (nnn.nnn.nnn.nnn notation)
# $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)
NODE=`echo ${1} | sed 's/::ffff://'`
PORT=${2}

PIDFILE="/var/run/`basename ${0}`.${NODE}_${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

# set the value for the Host header based on IP
# (defaults to IP address if IP doesn't match)
case "$NODE" in
  "192.168.1.1")
    HOST="host1.domain.com"
    ;;
  "192.168.1.2")
    HOST="host2.domain.com"
    ;;
  "192.168.1.3")
    HOST="host3.domain.com"
    ;;
  *)
    HOST="$IP"
    ;;
esac

# send request & check for expected response
if [ -v DATA ]; then
    curl -fNs http://${NODE}:${PORT}${URI} -H "Host: ${HOST}" -d "${DATA}" | grep -i "${RECV}" 2>&1 > /dev/null
else
    curl -fNs http://${NODE}:${PORT}${URI} -H "Host: ${HOST}" | grep -i "${RECV}" 2>&1 > /dev/null
fi

# mark node UP if expected response was received
if [ $? -eq 0 ]
then
    # Remove the PID file
    rm -f $PIDFILE

    # Echo anything to STDOUT to indicate success
    echo "UP"
else
    # Remove the PID file and exit
    rm -f $PIDFILE
    exit
fi
Published Mar 12, 2015
Version 1.0

Was this article helpful?