For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

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