A fun, but not well known, feature on BIG-IP is the Statistics Profile. This tech tip is the second in a series on how the Statistics Profile and iRules, when working together, can save time, productivity, and your sleep!

The Scenario:

Imagine yourself, Mr./Mrs. IT Manager, working for a company that's business relies on updated content on it's back-end web servers. Your company has a web team that has decided that it's test cycle will always end at 3:00AM (your time) on Saturday morning. So, here you are, arriving at home after a night of wild karaoke and one too many drinks with cheap umbrellas and you get a call from the dev team that they need the site taken off line so they can push out the new content.

In the past, you gave the dev lead the keys to the castle (meaning the admin credentials for your BIG-IP) and he/she somehow thought "rm -rf /" was how you took a virtual server offline. After an emergency restore of the software you vowed to never give that department direct access to your servers - ever... So, now you are stuck with being on call whenever they deem updates are needed. If only, you could provide your dev team access to control taking their application offline while they are doing updates. Oh, and they should also be able to view the current status as well as being able to bring it back online.

Never fear, help is on the way! There are a couple of handy features within iRules that make this problem a thing of the past.

The Setup:

To get things going, you'll need a Virtual Server setup fronting your web application. Since your application is up and running, that step is already taken care of. Next, you'll need to create a Statistics Profile, assign it to your Virtual Server and write an iRule. So, first we'll create the statistics profile...

Create the Statistics Profile

  • Login to the BIG-IP Administrative GUI.
  • Select the Profiles option under Local Traffic and Virtual Servers
  • Select the Statistics from the Other menu.
  • Click the Create button
  • Enter "maintenance_window" for the Profile name
  • Add the following fields: day, start_time, end_time
  • Click Update to create the profile

Create the iRule

Now that the virtual server is setup with the statistics profile, you'll need to create an iRule to to add the controlling functions as well as the maintenance window enforcement.

  • Select Rules from the Local Traffic/Virtual Servers menu.
  • Click the Create button.
  • Enter "maintenance_window" for the iRule name and enter the iRule from below into the Definition text box.
  • Click Finished to save the iRule

Apply the statistics profile to your virtual server

The statistics profile doesn't do much until you apply it to your virtual server properties. Here's how:

  • Select Virtual Servers from the Local Traffic menu.
  • Click on your Virtual Server to enter it's properties
  • Make sure the Advanced Configuration option is selected, and scroll down to the Statistics Profile option
  • Select the previously created profile maintenance_window
  • Click the Update Button
  • Select the Resources Menu
  • Click the Manage Rules button
  • Make sure the maintenance_window iRule is in the Enabled list box and click the Finished button.

The iRule

Now for the fun, here's the iRule that will give you peace, tranquility (and a good nights sleep). This iRule will look for commands in the URI to control the maintenance window settings (see the "/usage" section for details).

when HTTP_REQUEST {
  set TITLE "iRule Maintenance Window Control"
  set PROFILE_NAME "maintenance_window"

  # Look for embedded commands to control the maintenance window.

  switch -glob [string tolower [HTTP::uri]] {
    "/enable*" {

      # Extract the maintenance window day, start time, and end time from the URI. 
      # If not there, return an error message.

      set params [split [HTTP::uri] "/"]
      if { [llength $params] < 5 } {
        HTTP::respond 200 content "
          <head><center><title>$TITLE</title>
          <body><h1>Usage: http://[HTTP::host]/enable/day_number/start_hour/end_hour</h1>
          </body></html>"
      } else {

        # Update the maintenance window values in the statistics profile.

        STATS::set $PROFILE_NAME "day" [lindex $params 2]
        STATS::set $PROFILE_NAME "start_time" [lindex $params 3]
        STATS::set $PROFILE_NAME "end_time" [lindex $params 4]
        HTTP::respond 200 content "
          <head><center><title>$TITLE</title>
          <body><h1>Maintenance Window enabled</h1>
          </body></html>"
      }
    }
    "/disable" {

      # By zero'ing out the values in the statistics profile, the maintenance window is not enforced.

      STATS::set $PROFILE_NAME "day" 0
      STATS::set $PROFILE_NAME "start_time" 0
      STATS::set $PROFILE_NAME "end_time" 0
      HTTP::respond 200 content "
        <head><center><title>$TITLE</title>
        <body><h1>Maintenance Window disabled</h1>
        </body></html>"
    }
    "/check" {

      # Return the current time and the current settings for the maintenance window

      set day [STATS::get $PROFILE_NAME "day"]
      set start_time [STATS::get $PROFILE_NAME "start_time"]
      set end_time [STATS::get $PROFILE_NAME "end_time"]
      set l [split [clock format [clock seconds] -format {%u %H %M}] " "]
      set cur_day [lindex $l 0]
      set cur_time [expr [expr [lindex $l 1]*100] + [lindex $l 2]]
        HTTP::respond 200 content "
          <head><center><title>$TITLE</title>
          <body><h1>Current Date and time: $cur_day, $cur_time</h1>
            <h1>Maintenance Window: $day, $start_time - $end_time</h1>
          </body></html>"
    }
    "/usage" {

        # Usage instructions for the commands

        HTTP::respond 200 content "
          <head><center><title>$TITLE</title>
          <body><h1>Usage: http://[HTTP::host]/\[command\]</h1>
          <table><tr><td><ul>
            <li>/enable/day_of_week_number(1:mon-7:sun)/start_time(hhmm)/end_time(hhmm) - enable maintenance window.</li>
            <li>/disable - disable maintenance window.</li>
            <li>/check - check if in maintenance window.</li>
            <li>/usage - display this usage message</li>
          </ul></td></tr></table>
          </body></html>"
    }
    default {

      # no secret command entered, so check the maintenance window

      # Get the values from the statistics profile.
      set day [STATS::get $PROFILE_NAME "day"]
      set start_time [STATS::get $PROFILE_NAME "start_time"]
      set end_time [STATS::get $PROFILE_NAME "end_time"]

      if { ($day ne 0) and ($start_time ne 0) and ($end_time ne 0) } {

        # Use the TCL "clock" command to get the current time settings.
        set l [split [clock format [clock seconds] -format {%u %H %M}] " "]
        set cur_day [lindex $l 0]
        # Math right here is a bit overkill.  I've changed it to string concatenation.
        #set cur_time [expr [expr [lindex $l 1]*100] + [lindex $l 2]]
        set cur_time "[lindex $l 1][lindex $l 2]"
        if { ($cur_day eq $day) &&
           ($cur_time >= $start_time) &&
           ($cur_time <= $end_time) } {

          # The current time is in the maintenance window, so either issue a HTTP::redirect here to a
          # prettied up page, or you can do as I've done here, and return a HTML response direction
          # to the client.

          HTTP::respond 200 content "
            <head><center><title>$TITLE</title>
            <body><h1>This site is down for maintenance, please come back at $end_time ...</h1>
            </body></html>"

        } else {

          # Not in maintenance window, so allow connection to continue to application.

        }
      }
    }
  }
}

Conclusion:

So, now you should be all set. While your dev team now has control over their site's availability and the 3:00am calls are a thing of the past...