Forum Discussion
redirect based on monitor status
I would like to have a process where I am able to redirect a user to site down for maintenance page based on status of monitor. My workflow would be using a monitor to check for the content of a file on a web server. If for example the response is "maintenance" I would like to then redirect users to a site down page. Once the content of the file change I would like to remove the site down for maintenance message.
Currently I use the following irule to put up a site down page if all members of a pool are down. Assuming that is not the case and the user has not provided a uri string I redirect them to a default login page.
when HTTP_REQUEST {
if { [active_members [LB::server pool]] == 0 } {
HTTP::redirect "http://example.com/error/sitedown.html"
} elseif { [HTTP::uri] equals "/" } {
HTTP::redirect "https://[HTTP::host]/myapp/login.jsp"
}
}
But note in this case it doesn't matter why the pool has no members. I am wondering if I can take action based on the monitor that failed.
10 Replies
- Angus_2141Historic F5 AccountHere is one way to meet this requirement I guess...
The default pool in this case has four nodes, I create a new pool with one node. I then assign a monitor to this node that checks for a file on the host in question. If the admin of that server modifies that file the monitor fails. At this time all four nodes in the default pool for this VIP are online and working as expected. So,in this scenario the following irule seems to work as I want meaning the server admin changes a file to indicate a desire to put the application into maintenance mode.
when HTTP_REQUEST {
if { [LB::status pool appllication-maintenance-pool member 192.168.5.5 443 ] eq "down" } {
log local0.info "Server marked down, maintenance page enabled"
HTTP::redirect "http://example.com/errors/maintenance.html"
} elseif { [active_members [LB::server pool]] == 0 } {
HTTP::redirect "http://example.com/errors/sitedown.html"
} elseif {[HTTP::uri] equals "/" } {
HTTP::redirect "https://[HTTP::host]/default/logon"
}
}
I was hoping to find a way to test for the results from a particular monitor against a node but so far I have not found that functionality. - nitass
Employee
But note in this case it doesn't matter why the pool has no members. I am wondering if I can take action based on the monitor that failed.i may misunderstand but doesn't receive disable string work?
sol12818: Using the Receive Disable String advanced configuration setting
http://support.f5.com/kb/en-us/solutions/public/12000/800/sol12818 - Kevin_Stewart
Employee
What you have already is a pretty interesting implementation. I'm assuming you have a separate pool and monitor for each member of the default pool? And testing those individually in the iRule?
Unfortunately, monitors do not currently return any information to iRules other that up/down status. Ultimately then, you need a way to reach into the management plane (where this information IS available) from the data plane (iRules), and there are a number of ways to do that. Here are a few ideas:
1. Maintain a (constantly updated) data group with pool member status information. When all of the pool members become unavailable, use an iRule to look into the data group for a reason.
2. Do the same thing with a stats profile - use a numbering system (ex. 0 = up, 1 = down, 2 = maintenance). The cool thing about a stats profile is 1) it can be written to and read from both planes, and 2) doesn't require a config update (like the data group option) every time it's updated.
3. Do the same thing with a session table - have a monitor push data to a session table (through a services VIP). This one requires a services VIP and iRule to catch the management plane (cURL) requests and post them to the table. This one also doesn't require config updates.
4. Sideband calls - given that you're only doing this process when all members are down, a sideband call could roll through the pool members looking for the "maintenance" flag.
There are of course many other ways to get data to/from the management plane to an iRule, but also consider this one other option. First, I'm also assuming you're waiting until all pool members are down and then splashing a maintenance page if at least one of them is in a maintenance mode. I would perhaps question whether it was a good idea to allow server maintenance to happen this way, second, simply display a maintenance page as a de facto response to all members down, and last, perhaps manage your maintenance mode events at the BIG-IP (explicitly) by using something like a data group flag (ex. maintmode := 1) to trigger the maintenance mode action when you've scheduled an outage. - ag_g_2058
Nimbostratus
Hi Kevin and Nitass,
First off thanks for your input. As it turns out I had not really stopped to consider the disable string functionality until Nitass pointed it out to me. That is basically what I am looking for but I had not realized it was available until today. Based on that knowledge I played around a little bit today until I got the following basic irule to work.
when HTTP_REQUEST {
if { [LB::status pool application-maintenance-pool member 192.168.2.1 443 ] eq "session_disabled" } {
log local0.info "Server marked disabled, maintenance page enabled"
HTTP::redirect "http://example.com/errors/maintenance.html"
}
}
This is great but as I was considering this sitaution again today I realized that historically my logic has been a bit confused regarding monitors and status changes. In the past I have been using simple file monitors that check for the contents of a file and if that check fails the respective node is pulled from pool. This was being used by administrators to pull hosts from their pools on demand. However, what I really wanted was the stop accepting new connections and let the existing connections complete their session and for this I shoud have been using the "recv disable" response.
So, with this new knowledge and much to Kevin's point I wonder if it is a good idea to splash a maintenance page based on the status of a single node in the pool. I think a better plan is to allow all nodes in the pool to return a "session_disabled" status. At at this point I would like to put up a site down for maintenance page for any new connections.
The other conditional here woud be that if alll nodes in a pool return a "down" status then I would like to put up a "sorry we are experiencing technical difficulties" page.
The problem I have now is how to confirm that all nodes in a pool are in a disabled status. The following code is close but I do not have a way to test the total response from a pool.
when HTTP_REQUEST {
if { [LB::status pool testapp-pool member 192.168.2.1 443 ] eq "session_disabled" } {
log local0.info "Server marked disabled, maintenance page enabled"
HTTP::redirect "http://example.com/errors/maintenance.html"
} elseif { [active_members [LB::server pool]] == 0 } {
HTTP::redirect "http://example.com/errors/sitedown.html"
log local0.info "no active enabled members in pool, site down enabled"
} elseif {[HTTP::uri] equals "/" } {
HTTP::redirect "https://[HTTP::host]/default/logon"
}
I tried to use something like [ LB::status ] eq "session_disabled" but this did not seem to evaluate the pool which I sort of expected as the status argument assumes the node has already been selected. But maybe that is how I should start my loop assuming that is an option.
Thanks. - nitass
Employee
The problem I have now is how to confirm that all nodes in a pool are in a disabled status. The following code is close but I do not have a way to test the total response from a pool. can you try something like this?
e.g.[root@ve10:Active] config b virtual bar list virtual bar { snat automap pool foo destination 172.28.19.252:80 ip protocol 6 rules myrule profiles { http {} tcp {} } } [root@ve10:Active] config b pool foo list pool foo { members { 200.200.200.101:80 { session user disabled } 200.200.200.111:80 { session user disabled } } } [root@ve10:Active] config b rule myrule list rule myrule { when HTTP_REQUEST { set is_disabled 1 foreach poolmbr [members -list [LB::server pool]] { if { [eval "LB::status pool foo member $poolmbr"] ne "session_disabled" } { set is_disabled 0 break } } if { $is_disabled } { HTTP::respond 302 noserver Location "http://www.google.com/" } } } test [root@ve10:Active] config b pool foo|grep -i pool\ member +-> POOL MEMBER foo/200.200.200.101:80 active,unchecked +-> POOL MEMBER foo/200.200.200.111:80 active,unchecked [root@ve10:Active] config curl -i http://172.28.19.252 HTTP/1.0 302 Found Location: http://www.google.com/ Connection: Keep-Alive Content-Length: 0 - Angus_2141Historic F5 AccountHi Nitass,
This works great and is really what I am working towards. I will expand the functionality to allow for a default behavior based on the monitor response allowing for a maintenance page and a technical issues type page.
The one additional issue I am struggling with now is that if I put all nodes in "disable mode" and then return a "maintenance" page I will interrupt existing sessions. I am wondering about trying to use something like LB:persist to determine if the client already has a session and if so allow them to age off normally but redirect any new sessions to the maintenance page. I tried to set a variable in a similar fashion to the is_disabled object and then make decision based on this value. However, I don't seem to be finding a session when I expect to using this function.
set client_session [LB::persist]
if { lindex $client_session 1 ] eq "0" }…
I tried this to see if I have a session
when HTTP_REQUEST {
set $client_session [ LB::persist ]
log local0. "The persistence entry is: $client_session and the key is [LB::persist key]"
}
But I don't see values for the key or value.
However, maybe there is a better way to try and determine if a client already has an active session?
Thanks. - nitass
Employee
The one additional issue I am struggling with now is that if I put all nodes in "disable mode" and then return a "maintenance" page I will interrupt existing sessions. I am wondering about trying to use something like LB:persist to determine if the client already has a session and if so allow them to age off normally but redirect any new sessions to the maintenance page. I tried to set a variable in a similar fashion to the is_disabled object and then make decision based on this value. However, I don't seem to be finding a session when I expect to using this function. are you talking about persistence record? if yes, can you try "persist lookup"?
persist wiki
https://devcentral.f5.com/wiki/irules.persist.ashx
please be noted that some persistence method does not utilize persistence table (i.e. in memory) such as cookie. - Angus_2141Historic F5 AccountYes, I was thinking about checking for a persistence record but you are correct in most cases I have moved away from using the source IP for the persistance method in favor of using an F5 generated cookie. I suppose I could have a rule that checks for a persistence record and one that checks for a cookie to determine even the client should be redirected to a "maintenance" page.
But, do you have a better idea for how I can determine if this is a new client request or one from an existing session? Should I be looking at trying to use this function? https://devcentral.f5.com/wiki/iRules.session.ashx
It looks like this irule includes the logic to check for an existing session https://devcentral.f5.com/wiki/iRules.HTTPSessionLimit.ashx
Do you think it makes sense to use something like if {[HTTP::cookie exists "ClientID"]} as shown in the previous irule example?
Thanks. - marco_octavian_
Nimbostratus
"When set to Disabled, a node or pool member continues to process persistent and active connections. It can accept new connections only if the connections belong to an existing persistence session." - SOL13310
It shouldn't matter if you put the node into Disabled mode whether it is via an iRule or the gui. Having said this, I don't see the need to enhance the iRule with logic looking for persistent connection. - nitass
Employee
It shouldn't matter if you put the node into Disabled mode whether it is via an iRule or the gui. Having said this, I don't see the need to enhance the iRule with logic looking for persistent connection.i might be wrong but i understand he is using irule to redirect to maintenance page. so, persistent or existing session will be affected by the irule.
But, do you have a better idea for how I can determine if this is a new client request or one from an existing session? Should I be looking at trying to use this function? https://devcentral.f5.com/wiki/iRules.session.ashx yes, you can try. anyway, since cookie is not kept in bigip, how do you know when all existing clients are gone?
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