LTM Maintenance Page Lite

Problem this snippet solves:

Use the LTM as a webserver as a lite version of a maintenance page. In this case, it returns a maintenance page with text to return when the pool members are not available. Also refreshes the client's browser, every x seconds, returning back to the site, in case the site returns to normal after an outage or maintenance.

Contribution

The Bhattman, working off Spark's LTM Maintenance Page which is also based off several other contributors including citizen_elah

Code :

when HTTP_REQUEST {

   # sets the timer to return client to host URL
   set stime 10

   # Use the Host header value for the responses if it's set.  If not, use the VIP address.
   if {[string length [HTTP::host]]}{
      set host [HTTP::host]
   } else {
      set host [IP::local_addr]
   }

   # Check if the URI is /maintenance
   switch [HTTP::uri] {
      "/maintenance" {

         # Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
         HTTP::respond 200 content \
"Maintenance page\

Sorry! This site is down for maintenance.

" "Content-Type" "text/html" return } } # If the pool_testLB is down, redirect to the maintenance page if { [active_members pool_testLB] < 1 } { HTTP::redirect "http://$host/maintenance" return } }
Published Mar 18, 2015
Version 1.0
  • This seems utterly useless. How do you use this code. It doesn't even say where to put the code!
  • Its called an iRule, and it is not utterly useless, I use it in a couple of places in our network.
  • I tried this code in an iRule and it redirects to /maintenance but it just displays "This page cannot be displayed".

     

  • Hi,

     

    I understand why there are some issues with this code... the code is not generic, it use some useless static configuration : pool name, http protocol...

     

    Redirect must never include host and protocol if the target service is the same as current.

     

    I changed the redirect and refresh URL to relative URL. the pool name is the one assigned to the tcp connection. I also change the refresh URL to previous URI and not /. this allow user to follow browsing and not go back to home page.

     

    when RULE_INIT {
         sets the timer to return client to host URL
        set static::stime 10
    }
    
    when CLIENT_ACCEPTED { 
        set default_pool [LB::server pool]
    }
    
    when HTTP_REQUEST {
        Check if the URI is /maintenance
       switch [HTTP::uri] {
          "/maintenance" {
    
              Send an HTTP 200 response with a Javascript meta-refresh pointing to the host using a refresh time
             HTTP::respond 200 content \
    "Maintenance page\
    Sorry! This site is down for maintenance." "Content-Type" "text/html" 
             return
          }
       }
        If the default pool is down, redirect to the maintenance page
       if { [active_members $default_pool] < 1 } {
          HTTP::redirect "/maintenance"
          return
       }
    }
    
  • In this case static::stime in RULE_INIT is not useful. If you don't require global initialisation parameters across the box visible to every single iRule then don't use RULE_INIT.

     

    set stime 10 in CLIENT_ACCEPTED is functionally equivalent and scoped to the virtual server that is using your iRule.

     

  • Hi Kevin,

     

    creating static::stime in RULE_INIT is executed only when irule is modified or loaded.

     

    creating stime in CLIENT_ACCEPTED is executed for every new TCP connection.

     

    The goal of this irule is to create a generic behavior for every VS with this irule assigned. so static variable is the best solution.

     

    the only risk with static variables is multiple irule may not set different value of the same variable, the last which set the variable win. :)

     

  • Hi,

    why should I add prefix /maintenance? Why shoukd I make redirect HTTP::redirect "/maintenance"?

    Could iRule looks like this below, without redirection. What benefits are when I make this redirection.

    when HTTP_REQUEST {

    if {[active_members [LB::server pool]] < 1} {

      switch [string tolower [HTTP::uri]] {
             "/style.css" {
        HTTP::respond 200 content [ifile get "style"] "Content-Type" "text/css"
        } 
        default {
            HTTP::respond 200 content [ifile get "index"] "Content-Type" "text/html"
        }
     }
    

    } }

  • the benefits of using redirect is to be sure your logo file and css file are dedicated for the maintenance page.

     

    imagine your application with /style.css file.

     

    when you have no more active member, will the browser download this one or will it use the one from cache?

     

    /maintenance folder may not be used on server side...

     

    you also can have the same issue with maintenance page. which can be cached on client browser. with your irule, you have to manage client cache by adding cache-control header (and others) to be sure the maintenance page won't be cached.

     

    another issue with your code is if server is unavailable generating the maintenance page, but the server goes up before style.css is requested... --> the style.css won't match the irule and the maintenance page won't display as expected...

     

  • Don’t use switch unless you have at least 3 or more options as it is slower than a chain of if, elseif, else commands.

     

    Also look at using iFiles to store the html, css, and images, we do this currently and is very effective and easy to maintain as providing some separation of code and content.

     

  • I have also another question. You are using autorefresh defined in html head. In definition it return to the main page or uri. The problem is what hepend when you will not use autorefresh. If the client in his browser try to refresh using f5 key will refresh maintenece page and will never return to the main page without modyfication uri in browser (delete /maintenece text). Am I right? Is any workaround?