Forum Discussion
variable getting reset during irule execution
'll try to be as descriptive as I can since I'm not well trained in our F5 load balancers ways. Basically I have an iRule that looks something like this(pseudocode):
when HTTP_REQUEST {
set host_num 0
if uri contains /serv prefix
set host_num=(digit after /serv)
}
when LB_SELECTED {
if { $host_num != 0 } {
reselect the appropriate pool member that corresponds to the host_num
}
}
My problem is that my host_num variable is lost between when I set it in HTTP_REQUEST and when I actually need it in the LB_SELECTED event.
This system worked flawlessly for years. Until a few days ago when I tried to add another irule that forced all http traffic to be http 1.0 instead of 1.1. I've removed this irule, but this problem still remains. Is there a setting in the HTTP profile that I'm missing? I've checked my other irules and none of them have a host_num variable that could be overwriting this, so what could be happening?
10 Replies
- nathe
Cirrocumulus
Chris,
I'm far from an expert at variables in iRules so my only suggestion would be creating a global variable, rather than a local variable.
See this article about global variables: https://devcentral.f5.com/tech-tips/articles/irules-101-03-variables.UV2gXzd5g08
So, in your example it would be something like: "set ::host_num=(digit after /serv)" and then referenced thus: "if { $::host_num != 0 }"
Hope this helps,
N - Kevin_Stewart
Employee
A global variable would be global to the whole box (ie. everyone), so that wouldn't work. Are you saying that the check for $host_num in the LB_SELECTED event fails? Does it crash the iRule?
Try this to test and please report the results:when HTTP_REQUEST { log local0. "here" set host_num 0 } when LB_SELECTED { log local0. "here" if { [info exists host_num] } { log local0. "host_num exists" } else { log local0. "host_num does not exist" } } - Chris_R_123579
Nimbostratus
I used your test code and host_num does exist. I don't ever see a host_num does not exist in my logs.
But my problem occurs in my irule like so:when HTTP_REQUEST { log local0. "here" set host_num 0 if { [string tolower $uri] starts_with "/serv" } { log local0. "prefix redirect initiated" if { [string tolower $uri] matches_regex {serv[\d]+} } { scan $uri /serv%d host_num set path "/" log local0. "uri match found $host_num" } else { scan $uri /serv%d%s host_num path log local0. "uri match not found assert $host_num" } HTTP::uri $path } when LB_SELECTED { log local0. "LB here" if { $host_num != 0 } { redirect the request to the appropriate member switch $host_num { 1 { LB::reselect pool SERV member 10.10.10.2 log local0. "prefix redirect selecting /serv1" } } }My problem occurs when LB_SELECTED executes. For some reason $host_num is always being reset to 0.
It's almost like any user who tries to use the prefix redirect to select a specific server, will get the host_num variable set, but before the LB_SELECT function executes the session/connection is cleared and they get host_num = 0 or something.
Any ideas? - Kevin_Stewart
Employee
I'm a little curious about your if conditional:
if { [string tolower $uri] matches_regex {serv[\d]+} } {
You're saying that if there's a number after the /serv URI, set the host_name and the path. But then in the else condition, you have this: scan $uri /serv%d%s host_num path. This assumes there's a number after the /serv URI, followed by a path. I would think that host_num wouldn't be set in this condition, considering the /serv URI doesn't have a number after it.
Can you try this minor variation:when HTTP_REQUEST { log local0. "here" set host_num 0 set path "/" if { [string tolower [HTTP::uri]] starts_with "/serv" } { log local0. "prefix redirect initiated" if { [string tolower [HTTP::uri]] matches_regex {serv[\d]+} } { scan [string tolower [HTTP::uri]] /serv%d%s host_num path log local0. "uri match found: $host_num" } else { scan [string tolower [HTTP::uri]] /serv%s path } log local0. "path = $path" HTTP::uri $path } } when LB_SELECTED { log local0. "here" if { [info exists host_num] } { log local0. "host_num exists: $host_num" if { $host_num != 0 } { switch $host_num { 1 { LB::reselect pool local-pool member 10.70.0.2 log local0. "prefix redirect selecting /serv1" } } } } else { log local0. "host_num does not exist" } } - Chris_R_123579
Nimbostratus
Thanks for the response. I made the changes and every time it checks for host_num existance in the LB_SELECTED event, hust_num is 0.
I get the following in my logs on one request to example.com/serv1
Thu Apr 4 16:15:42 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : path = /
Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : uri match found: 2
Like I said, this irule worked flawlessly for 4 or 5 years and then one day I threw in a new iRule that had some chunking/http1.0 changes(which has been removed for over a week) and its been messed up since then.
Thanks again - Kevin_Stewart
Employee
Can you share your entire iRule?
Have you or can you reboot the BIG-IP (or do a bigstart restart)? - Chris_R_123579
Nimbostratus
Here is the entire rule with IP's changed etc. But this is the meat of it.when HTTP_REQUEST { set uri [HTTP::uri] set host_num 0 set req_cookie [HTTP::cookie "DEVPERSIST"] if { [string tolower $uri] starts_with "/serv" } { if { [string tolower $uri] matches_regex {serv[\d]+} } { scan $uri /serv%d host_num set path "/" } else { scan $uri /serv%d%s host_num path } snip the host prefix from the URI HTTP::uri $path remove the cookie if it's there if { [HTTP::cookie exists DEVPERSIST] } { HTTP::cookie remove DEVPERSIST } } } when LB_SELECTED { if { $host_num != 0 } { log local0. "hostnum here $host_num" redirect the request to the appropriate member switch $host_num { 1 { LB::reselect pool DEV member 10.10.10.2:7085 } 2 { LB::reselect pool DEV member 10.10.10.3:8080 } } } } when HTTP_RESPONSE { if { $host_num != 0 } { HTTP::header insert Set-Cookie "DEVPERSIST=[HTTP::cookie DEVPERSIST]; Path=/" log local0. "hostnum here $host_num" } }
I haven't rebooted the F5 yet since it serves about 30 different high usage web applications. But I can talk to our sys admins about doing so at some point. - Kevin_Stewart
Employee
Fundamentally I don't see anything wrong with the logic. I'm still curious about your else condition though, given that there won't be a number after /serv if this condition is met. I would recommend a bigstart restart on the assumption that NOTHING else has changed other than applying and then removing some iRule logic.
Can you also try this variation of your rule:when HTTP_REQUEST { set host_num 0 set req_cookie [HTTP::cookie "DEVPERSIST"] set path "/" if { [string tolower [HTTP::uri]] starts_with "/serv" } { log local0. "starts with /serv" if { [string tolower [HTTP::uri]] matches_regex {/serv[\d]+} } { log local0. "match_regex" scan [string tolower [HTTP::uri]] /serv%d%s host_num path log local0. "host_num = $host_num" log local0. "path = $path" } else { log local0. "not match_regex" scan [string tolower [HTTP::uri]] /serv%s path log local0. "path = $path" } snip the host prefix from the URI HTTP::uri $path remove the cookie if it's there if { [HTTP::cookie exists DEVPERSIST] } { HTTP::cookie remove DEVPERSIST } } } when LB_SELECTED { if { $host_num != 0 } { log local0. "hostnum here $host_num" redirect the request to the appropriate member switch $host_num { 1 { log local0. "selecting member 1" LB::reselect pool DEV member 10.10.10.2:7085 } 2 { log local0. "selecting member 2" LB::reselect pool DEV member 10.10.10.3:8080 } } } else { log local0. "hostnum = 0" } } when HTTP_RESPONSE { if { $host_num != 0 } { HTTP::header insert Set-Cookie "DEVPERSIST=[HTTP::cookie DEVPERSIST]; Path=/" log local0. "hostnum here $host_num" } else { log local0. "hostnum = 0" } - Chris_R_123579
Nimbostratus
Thanks Kevin. I've scheduled a restart for Monday, so hopefully that solves it.
I'm not sure what that else logic is for either. The irule was written by my predecessor. - nathe
Cirrocumulus
Kevin "A global variable would be global to the whole box (ie. everyone), so that wouldn't work." - doh! I missed that key point about global variables. Back to the Variables 101 guide me thinks. Thanks
N
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