Forum Discussion
"Select pool based on uri content" iRule doesn't seem to be working
I have an iRule that is designed to select a pool based on a string found in the uri and it doesn't seem to be working. I have a log that collects the uri for reference. The "test" rule I have in place that searches the uri and creates the "destination pool name" seems to be creating the pool name correctly, but when I put the "action" rule into place the http request hangs. Background and iRules are provided below.
Background:
-The VIP is listening on port 80 and has a default pool listening on 8981
-The web application being load balanced is Tibco ESB
-There are 25 separate services that are supported by this application and all are listening on different ports
-Individual pools are created with basic http monitor showing all pool members as "up"
-Our pools have a naming convention that has a string before and after the service name. (i.e. esb__pool)
-Use of "uri" and "test" rules yield the following log entries:
Dec 1 08:37:28 tmm tmm[1097]: Rule esb_pool-uri-log : ====VIP uri request is /eProxy/service/CreditCardService?wsdl====
Dec 1 08:37:28 tmm tmm[1097]: Rule esb_pool-mgr_test : ==ESB Tibco: Requested pool name is esb_CreditCardService_pool==
-Use of the "uri" and "action rules yield the following log entries:
ec 1 08:43:36 tmm tmm[1097]: Rule esb_pool-uri-log : ====VIP uri request is /eProxy/service/CreditCardService?wsdl====
Dec 1 08:43:36 tmm tmm[1097]: Rule esb_pool-mgr_action : ==ESB Tibco: Requested pool name is esb_CreditCardService_pool==
iRules:
"uri logging rule"
rule esb_pool-uri-log {
when HTTP_REQUEST {
set esb_uri [HTTP::uri]
log local0. "===="
log local0. "====VIP uri request is $esb_uri===="
}
}
++++++++++++++++++++++++++
"pool selection test rule"
rule esb_pool-mgr_test {
when HTTP_REQUEST {
set front "esb_"
set back "_pool"
set svc_uri [getfield [HTTP::uri] ? 1]
set svc_name [getfield $svc_uri "dir1/service/" 2]
set pool_name [concat $front$svc_name$back]
log local0. "==ESB Tibco: Requested pool name is $pool_name=="
}
}
++++++++++++++++++++++++++
"pool selection action rule"
rule esb_pool-mgr_action {
when HTTP_REQUEST {
set front "esb_"
set back "_pool"
set svc_uri [getfield [HTTP::uri] ? 1]
set svc_name [getfield $svc_uri "dir1/service/" 2]
set pool_name [concat $front$svc_name$back]
log local0. "==ESB Tibco: Requested pool name is $pool_name=="
if { [catch { pool $pool_name } ] } {
log local0. "====ERROR: Attempting to assign traffic to non-existant pool $pool_name===="
log local0. "====Sending traffic to default esb pool===="
pool esb_8981_pool
}
}
}
Is there something I am missing that is not sending the traffic to the correct pool?
Thanks,
Kevin
14 Replies
- Colin_Walker_12Historic F5 AccountKevin,
The logs look correct, and the iRules don't have any obvious errors in them, either. Are you sure that the pools that the iRule is trying to send traffic to exists exactly as it's being called? Are there any other messages being logged to /var/log/ltm when you're trying to pass traffic via this iRule?
Colin - Festus_50639
Nimbostratus
Colin, thanks for the sanity check and reply.
That being said,,,
It seems that what the customer wants isn't exactly what was conveyed.
Here is what I'm left with to do:
1. Create a pool for each of the service end points - Done
2. Create a health monitor for each of the service end point pools - In progress
3. Create a string class containing the service end point names (for matching to pools) and service end point pool port numbers - Done (string entries in class are ":" and svc_name equals service pool name as noted in item 1.)
4. Create an iRule that compares the health of the selected node in the default pool (request entry point) and the health of the service end point on the same selected node and process the request if both values are "true" or reselect if either is false.
I have what I think is a completed iRule, but I'm getting an error that the command is out of context in regards to the bit below.
"when LB_SELECTED {
if { ([LB::status pool [LB::server pool] member [LB::server ip] [LB::server port]] eq "up") and ([LB::status pool $svc_pool member [LB::server ip] $svc_name-port] eq "up") }"
===iRule begin===
when HTTP_REQUEST {
pool esb_8981_pool
set sel_node [LB::server name]
set front "esb_"
set back "_pool"
set svc_name [getfield $svc_uri "eProxy/service/" 2]
set svc_pool [concat $front$svc_name$back]
foreach line $::esb_svc_name-port_class {
if {[string match [getfield $line ":" 1] $svc_name] } {
set svc_name-port [getfield $line ":" 2]}
}
when LB_SELECTED {
if { ([LB::status pool [LB::server pool] member [LB::server ip] [LB::server port]] eq "up") and ([LB::status pool $svc_pool member [LB::server ip] $svc_name-port] eq "up") } {
eval $sel_node
} else {
LB::reselct }
}
}
===iRule end=====
If someone could take a look at that iRule and tell me where my syntax is out of whack, I would surely appreciate it.
Thanks,
Kevin - hoolio
Cirrostratus
Hi Kevin,
Which LTM version are you running? Can you log the output of $svc_name-port and $sel_node before using them in the if statement in LB_SELECTED?
Thanks,
Aaron - Festus_50639
Nimbostratus
Aaron,
BigIP version information below:
Kernel:
Linux 2.4.21-9.3.0.178.0smp
Package:
BIG-IP Version 9.3.0 192.0
Hotfix HF2 Edition
In going over the iRule and DevCentral documentation regarding HTTP_REQUEST and LB_SELECTED, I'm finding that "LB::status" is not an allowed command for either of those two events. If I am reading the documentation correctly, I can only get LB::status under the LB_FAILED event.
Is there another event that happens BEFORE the request is processed where I can get LB::status of the LB::server?
What I need to do before the request is processed is to determine if the status of the selected node is "up" for both health monitors.
=========update=========
I thought that I might try using using "active_members -list" but found that I'm a few versions behind on that one.
Is there an alternative to "active_members -list" that would return the same information?
Also, is LB::status slated to be a valid command for LB_SELECTED? - hoolio
Cirrostratus
Hi Kevin,
LB::status should actually work in HTTP_REQUEST and LB_SELECTED. There were a few typos in your rule. LB::reselect was missing an 'e'. And there was a missing closing curly brace in HTTP_REQUEST and an extra one in LB_SELECTED. Also, I think you'll run into problems using a variable name with a hyphen:
% set test-var 10
10
% puts $test-var
can't read "test": no such variable
% puts ${test-var}
10
You could either reference the variable with curly braces or just change it to an underscore:when HTTP_REQUEST { pool $esb_8981_pool set sel_node [LB::server name] set front "esb_" set back "_pool" set svc_name [getfield $svc_uri "eProxy/service/" 2] set svc_pool [concat $front$svc_name$back] foreach line $::esb_svc_name_port_class { if {[string match [getfield $line ":" 1] $svc_name] } { set svc_name_port [getfield $line ":" 2] } } } when LB_SELECTED { if { ([LB::status pool [LB::server pool] member [LB::server addr] [LB::server port]] eq "up")\ and ([LB::status pool $svc_pool member [LB::server addr] $svc_name_port] eq "up") } { eval $sel_node } else { LB::reselect } }
Aaron - Festus_50639
Nimbostratus
Thanks Aaron,
I have swapped the hyphen with and underscore and that seems to have resolved that issue.
I also replaced the "foreach" loop with a cleaner "findclass" command (shown here)
====old way to set variable==
foreach line $::esb_svc_name-port_class {
if {[string match [getfield $line ":" 1] $svc_name] } {
set svc_name_port [getfield $line ":" 2]}
}
====================
====new way to set variable==
set svc_name_port [findclass $svc_pool $::esb_svc_name_port_class ":"]
====================
Here is what the iRule now looks like
===========current iRule iterration=============
when HTTP_REQUEST {
pool esb_8981_pool
set front "esb_"
set back "_pool"
set svc_uri [getfield [HTTP::uri] ? 1]
set svc_name [getfield $svc_uri "eProxy/service/" 2]
set svc_pool [concat $front$svc_name$back]
set svc_name_port [findclass $svc_pool $::esb_svc_name_port_class ":"]
}
when LB_SELECTED {
log local0. "==ESB Tibco: initial lb selection is [LB::select]=="
if { ([LB::status pool [LB::server pool] member [LB::server addr] [LB::server port]] eq "up")\
and ([LB::status pool $svc_pool member [LB::server addr] $svc_name_port] eq "up") } {
eval [LB::select]
} else {
LB::reselect
}
log local0. "==ESB Tibco: final lb selection was [LB::select]=="
}
======================================
It seems to be working as expected, except that when I look at the logs created, it seems to be reselecting the node to which traffic is being sent to even if both of my comparison values are TRUE.
============log samples===============
Dec 3 12:15:25 tmm tmm[1097]: Rule esb_PA-SVC_evaluation : ==ESB Tibco: initial lb selection is pool esb_8981_pool member 10.44.44.147 8981==
Dec 3 12:15:25 tmm tmm[1097]: Rule esb_PA-SVC_evaluation : ==ESB Tibco: final lb selection was pool esb_8981_pool member 10.44.44.162 8981==
==================================
The reselection is interesting and I'd like to figure that out as well.
Thanks again for the assistance.
Kevin - hoolio
Cirrostratus
I'm not sure why that would happen. Can you add a log statement to verify that both checks are evaluating to true?
I don't think you need to use LB::select if the cases are true. The load balancing selection will be used without intervention. Can you try removing the eval [LB::select] command and retesting with the additional logging?
Thanks,
Aaron - Festus_50639
Nimbostratus
After re-reading the documentation on LB::select and LB::server I realized I should have been using "LB::server" which is now working properly. I have since conducted functional testing on the iRule and monitor configuration and have found that they are functioning as expected.
My next step now is to move this to our DEV environment which means coming up with a script that will take an input file so that I can automate the creation of monitors and pools using the appropriate bigpipe commands. I've been trying to come up with an 'awk' solution to do that but seem to be running into issues with the "'{
Also, thanks for the help on getting this iRule hammered out. - hoolio
Cirrostratus
Out of curiosity, could you post your final rule? I'm curious to see what you ended up with.
Citizen_elah pointed out some handy syntax for adding objects via the command line. If you wrap the curly braces in single quotes, you don't have to escape the statements inside:
b virtual my_test_vip '{
pool http_pool
destination 1.1.1.1:80
profiles http tcp
}'
Aaron - Festus_50639
Nimbostratus
Here is the current final draft on my rule.
I have some logging functions in there to show what's going on until I get final buyoff from the customer.
when HTTP_REQUEST {
pool esb_8981_pool
set front "esb_"
set back "_pool"
set svc_uri [getfield [HTTP::uri] ? 1]
set svc_name [getfield $svc_uri "eProxy/service/" 2]
set svc_pool [concat $front$svc_name$back]
set svc_name_port [findclass $svc_pool $::esb_svc_name_port_class ":"]
}
when LB_SELECTED {
following log items used for buyoff testing Will be removed once accepted
set PA_status [LB::status pool [LB::server pool] member [LB::server addr] [LB::server port]]
set SVC_status [LB::status pool $svc_pool member [LB::server addr] $svc_name_port]
log local0. "==ESB Tibco: Policy agent server selected is [LB::server addr] and status is $PA_status=="
log local0. "==ESB Tibco: Service agent server selected is [LB::server addr] and status is $SVC_status=="
if { (([LB::status pool [LB::server pool] member [LB::server addr] [LB::server port]] eq "up") and ([LB::status pool $svc_pool member [LB::server addr] $svc_name_port] eq "up")) } {
pool esb_8981_pool [LB::server addr] [LB::server port]
} else {
additional buyoff test logging
log local0. "==PA svc for [LB::server addr] was $PA_status and SVC port was $SVC_status=="
log local0. "==A different server has been selected=="
LB::reselect
}
}
As for adding objects via the command line, I'm trying to script the creation of those objects and individually it is no problem. The problem occurs when I try to pass variables to the bigpipe command. I am looking for the exact error I got, but it essentially said that the bigpipe command does not accept variables.
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