Forum Discussion
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
- The_Bhattman
Nimbostratus
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 - nitass
Employee
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
Altostratus
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 - The_Bhattman
Nimbostratus
Hi Rob,
This looks good. I don't see anything wrong with your approach.
Bhattman
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
