Forum Discussion

RobS's avatar
RobS
Icon for Altostratus rankAltostratus
Jan 15, 2013

Combining iRules for maintenance page with 503 code

I don't have to do iRules too often so I'm not sure if this is possible combined into one iRule, doable via two, or not possible at all. I created an iRule for my maintenace page and it works well:

 

when HTTP_REQUEST {

 

if { [HTTP::uri] eq "/" } {

 

HTTP::respond 200 content [ifile get f5maint_txt]

 

} elseif { [HTTP::uri] eq "/favicon.ico" } {

 

HTTP::respond 200 content [ifile get favicon_ico]

 

} elseif { [HTTP::uri] eq "/reset.css" } {

 

HTTP::respond 200 content [ifile get reset_css]

 

} elseif { [HTTP::uri] eq "/style_main.css" } {

 

HTTP::respond 200 content [ifile get style_main_css]

 

} elseif { [HTTP::uri] eq "/jquery.js" } {

 

HTTP::respond 200 content [ifile get jquery_js]

 

} elseif { [HTTP::uri] eq "/jquery.jfeed.pack.js" } {

 

HTTP::respond 200 content [ifile get jquery.jfeed.pack_js]

 

} elseif { [HTTP::uri] eq "/head.js" } {

 

HTTP::respond 200 content [ifile get head_js]

 

} elseif { [HTTP::uri] eq "/search.js" } {

 

HTTP::respond 200 content [ifile get search_js]

 

} elseif { [HTTP::uri] eq "/image_topbarleft.jpg" } {

 

HTTP::respond 200 content [ifile get image_topbarleft_jpg]

 

} elseif { [HTTP::uri] eq "/image_topbarright.jpg" } {

 

HTTP::respond 200 content [ifile get image_topbarright_jpg]

 

} elseif { [HTTP::uri] eq "/image_navtop.jpg" } {

 

HTTP::respond 200 content [ifile get image_navtop_jpg]

 

} elseif { [HTTP::uri] eq "/logo_main.png" } {

 

HTTP::respond 200 content [ifile get logo_main_png]

 

} elseif { [HTTP::uri] eq "/image_contactbkg.png" } {

 

HTTP::respond 200 content [ifile get image_contactbkg_png]

 

} else { discard }

 

}

 

 

I tried to add the code for when all pool members are down:

 

when HTTP_REQUEST {

 

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

 

log local0. "Server Pool: [LB::server pool]"

 

HTTP::respond 200 content [ifile get f5maint_txt]

 

} elseif { [HTTP::uri] eq "/favicon.ico" } {

 

HTTP::respond 200 content [ifile get favicon_ico]

 

} elseif { [HTTP::uri] eq "/reset.css" } {

 

HTTP::respond 200 content [ifile get reset_css]

 

} elseif { [HTTP::uri] eq "/style_main.css" } {

 

HTTP::respond 200 content [ifile get style_main_css]

 

} elseif { [HTTP::uri] eq "/jquery.js" } {

 

HTTP::respond 200 content [ifile get jquery_js]

 

} elseif { [HTTP::uri] eq "/jquery.jfeed.pack.js" } {

 

HTTP::respond 200 content [ifile get jquery.jfeed.pack_js]

 

} elseif { [HTTP::uri] eq "/head.js" } {

 

HTTP::respond 200 content [ifile get head_js]

 

} elseif { [HTTP::uri] eq "/search.js" } {

 

HTTP::respond 200 content [ifile get search_js]

 

} elseif { [HTTP::uri] eq "/image_topbarleft.jpg" } {

 

HTTP::respond 200 content [ifile get image_topbarleft_jpg]

 

} elseif { [HTTP::uri] eq "/image_topbarright.jpg" } {

 

HTTP::respond 200 content [ifile get image_topbarright_jpg]

 

} elseif { [HTTP::uri] eq "/image_navtop.jpg" } {

 

HTTP::respond 200 content [ifile get image_navtop_jpg]

 

} elseif { [HTTP::uri] eq "/logo_main.png" } {

 

HTTP::respond 200 content [ifile get logo_main_png]

 

} elseif { [HTTP::uri] eq "/image_contactbkg.png" } {

 

HTTP::respond 200 content [ifile get image_contactbkg_png]

 

} else { discard }

 

}

 

Now the page doesn't work even when the pool members are available. The iRule shouldn't even process if the members are up I would think so I'm sure I've done something wrong here.

 

I also want to return a status of 503 Service Unavailable in case google crawls while the maintenance page is active. I found the below code but have no idea how to integrate it or if it needs to be an additional iRule on the same VS:

 

when HTTP_REQUEST_SEND {

 

TCP::collect 32

 

log local0. "Added header"

 

 

}

 

when SERVER_DATA {

 

if {[findstr [TCP::payload 32] "200"] == "200"} {

 

TCP::payload replace 9 23 "503 Service Unavailable"

 

}

 

}

 

when HTTP_RESPONSE {

 

HTTP::header replace Retry-After 10800

 

}

 

 

I greatly appreciate any assistance!

 

Thanks,

 

Rob

 

4 Replies

  • Hi Rob,

     

    I think I can assist on a portion of this.

     

     

    Recall the portion of the code you posted

     

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

     

     

    This should change to

     

    { [active_members pool] < 1] } were "pool" is your pool name

     

     

    You can find references to it on the irule code wiki (https://devcentral.f5.com/wiki/iRules.active_members.ashx)

     

     

    Also consider using the switch command

     

     

    For example you could re-write you code to the following using the switch statement which is more efficient then IF-ELSEIF-ELSE statement

     

     

    when HTTP_REQUEST {

     

    if { [active_members pool ] < 1] } {

     

    log local0. "Server Pool: [LB::server pool]"

     

    HTTP::respond 200 content [ifile get f5maint_txt]

     

    } else {

     

    switch -glob [string tolower[HTTP::uri]] {

     

    "/favicon.ico" { HTTP::respond 200 content [ifile get favicon_ico] }

     

    "/reset.css" { HTTP::respond 200 content [ifile get reset_css] }

     

    "/style_main.css" { HTTP::respond 200 content [ifile get style_main_css] }

     

    "/jquery.js" { HTTP::respond 200 content [ifile get jquery_js] }

     

    "/jquery.jfeed.pack.js" { HTTP::respond 200 content [ifile get jquery.jfeed.pack_js] }

     

    "/head.js" { HTTP::respond 200 content [ifile get head_js] }

     

    "/search.js" { HTTP::respond 200 content [ifile get search_js] }

     

    "/image_topbarleft.jpg" { HTTP::respond 200 content [ifile get image_topbarleft_jpg] }

     

    "/image_topbarright.jpg" { HTTP::respond 200 content [ifile get image_topbarright_jpg] }

     

    "/image_navtop.jpg" { HTTP::respond 200 content [ifile get image_navtop_jpg] }

     

    "/logo_main.png" { HTTP::respond 200 content [ifile get logo_main_png] }

     

    "/image_contactbkg.png" { HTTP::respond 200 content [ifile get image_contactbkg_png] }

     

    default { discard }

     

    }

     

    }

     

    }

     

     

     

     

    I hope this helps

     

    Bhattman

     

  • e.g.

    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm virtual bar
    ltm virtual bar {
        destination 172.28.20.14:80
        ip-protocol tcp
        mask 255.255.255.255
        pool foo
        profiles {
            http { }
            tcp { }
        }
        rules {
            myrule
        }
        source 0.0.0.0/0
        source-address-translation {
            type automap
        }
        vlans-disabled
    }
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm pool foo
    ltm pool foo {
        members {
            200.200.200.101:80 {
                address 200.200.200.101
                session monitor-enabled
                state down
            }
        }
        monitor fake
    }
    
     Controlling Bots 
     https://devcentral.f5.com/wiki/iRules.ControllingBots.ashx
    
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm rule myrule
    ltm rule myrule {
        when HTTP_REQUEST {
      if { [active_members [LB::server pool]] < 1 } {
        switch -glob [string tolower [HTTP::header User-Agent]] {
          "*scooter*" -
          "*slurp*" -
          "*msnbot*" -
          "*fast-*" -
          "*teoma*" -
          "*googlebot*" {
            HTTP::respond 503 content "" noserver
            return
          }
       }
    
        switch [HTTP::path] {
          "/f5.gif" { HTTP::respond 200 content [ifile get f5_gif_ifile] noserver }
          default {
            HTTP::respond 200 content [ifile get maint_html_ifile] noserver
          }
        }
      }
    }
    }
    
     maintenance page
    
    [root@ve11a:Active:Changes Pending] config  curl -i http://172.28.20.14
    HTTP/1.0 200 OK
    Connection: Keep-Alive
    Content-Length: 97
    
    
    
    
    This is maintenance page.
    
    
    
    
     googlebot
    
    [root@ve11a:Active:Changes Pending] config  curl -i http://172.28.20.14 -H "User-Agent: googlebot"
    HTTP/1.0 503 Service Unavailable
    Connection: Keep-Alive
    Content-Length: 0
    
     normal page
    
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) modify ltm pool foo monitor none
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm pool foo
    ltm pool foo {
        members {
            200.200.200.101:80 {
                address 200.200.200.101
            }
        }
    }
    
    [root@ve11a:Active:Changes Pending] config  curl -i http://172.28.20.14
    HTTP/1.1 200 OK
    Date: Wed, 16 Jan 2013 07:39:16 GMT
    Server: Apache/2.2.3 (CentOS)
    Last-Modified: Sat, 27 Oct 2012 03:22:35 GMT
    ETag: "4183f3-59-f28f94c0"
    Accept-Ranges: bytes
    Content-Length: 89
    Content-Type: text/html; charset=UTF-8
    
    
    
    
    This is 101 host.
    
    
    
    
  • RobS's avatar
    RobS
    Icon for Altostratus rankAltostratus
    Bhattman and nitass,

     

     

    Thanks for the responses! As a result I have come up with the following which does seem to be working (I built a test pool out of Cisco switches with http enabled which I disable for the test):

     

     

    when HTTP_REQUEST {

     

    if { [active_members F5_LB_Switches] < 1 } {

     

    switch -glob [string tolower [HTTP::header User-Agent]] {

     

    "*scooter*" -

     

    "*slurp*" -

     

    "*msnbot*" -

     

    "*fast-*" -

     

    "*teoma*" -

     

    "*googlebot*" {

     

    HTTP::respond 503 content "" noserver

     

    return

     

    }

     

    }

     

     

    switch -glob [string tolower [HTTP::uri]] {

     

    "/" { HTTP::respond 200 content [ifile get f5maint_txt] }

     

    "/favicon.ico" { HTTP::respond 200 content [ifile get favicon_ico] }

     

    "/reset.css" { HTTP::respond 200 content [ifile get reset_css] }

     

    "/style_main.css" { HTTP::respond 200 content [ifile get style_main_css] }

     

    "/jquery.js" { HTTP::respond 200 content [ifile get jquery_js] }

     

    "/jquery.jfeed.pack.js" { HTTP::respond 200 content [ifile get jquery.jfeed.pack_js] }

     

    "/head.js" { HTTP::respond 200 content [ifile get head_js] }

     

    "/search.js" { HTTP::respond 200 content [ifile get search_js] }

     

    "/image_topbarleft.jpg" { HTTP::respond 200 content [ifile get image_topbarleft_jpg] }

     

    "/image_topbarright.jpg" { HTTP::respond 200 content [ifile get image_topbarright_jpg] }

     

    "/image_navtop.jpg" { HTTP::respond 200 content [ifile get image_navtop_jpg] }

     

    "/logo_main.png" { HTTP::respond 200 content [ifile get logo_main_png] }

     

    "/image_contactbkg.png" { HTTP::respond 200 content [ifile get image_contactbkg_png] }

     

    default { discard

     

    }

     

    }

     

    }

     

    }

     

     

    Using curl with the User-Agent string with the bot names does come back with a 503 like I want. If you have another minute, please let me know if you see any major flaws.

     

     

    Thanks!

     

    Rob
  • Hi Rob,

     

    This looks good. I don't see anything wrong with your approach.

     

     

    Bhattman