Forum Discussion
iRule for handling traffic to multiple pools through the same VS
I tried searching for questions asked by people trying to do substantially the same thing I am and came up close ... but empty. I'm hoping someone here can help me out a bit. Here's the set-up:
We have multiple tools running on the same VMs, with each listening on different ports. They're accessible via URLs that share a common domain and may or may not include a subdomain. The URLs include a path, which is the name of the tool. Here are examples:
test.domain.com/tool-one
domain.com/tool-two
The tools each have their own pool in the F5 and, of course, the members are set to listen on different ports. For example, tool-one might be listening on port 10450, while tool-two might be listening on port 10502.
I've written an iRule that successfully parses the HTTP host header and the HTTP path header information to determine the pool to which to send the traffic. Examples:
test-tool-one
production-tool-two
This is the iRule that I wrote:
when RULE_INIT {
set ::domain ".domain.com"
}
when HTTP_REQUEST {
# The next 5 lines of code are used to determine the environment to which the user wishes to connect.
# If the domain matches the global domain variable,
# then we know the user is requesting a non-production environment
# and we extract the requested environment from the domain.
if { [string tolower [HTTP::host]] contains $::domain } {
set subdomain [getfield [HTTP::host] $::domain 1]
} else {
set subdomain "production"
}
# Remove the leading forward slash from the path.
set path [string trimleft [HTTP::path] ?/?]
# This enables us to connect to version.json for the tool.
# We explode the path on the forward slash, then grab the tool name from the list's first element
# and we don't care what was stored in path from the previous command.
set path_list [split $path "/"]
set path [lindex $path_list 0]
# This check enables us to serve either the correct tool
# OR a generic message informing the user we don't know which tool they want
# OR to simply pass the request through to the server, as appropriate.
if { $path contains "-" } {
# Send the user to the correct pool for the selected environment and tool
pool "$subdomain-$path"
} elseif { [HTTP::path] == "" || [HTTP::path] == "/" } {
# Send the user to the tool serving the generic "You're lost" message
# Yet to be created
}
# else omitted intentionally because we want to simply pass the traffic through using the existing connection
}
I have used logging to see the information I'm getting along the way. The tools can make several requests to the back-end VM for things like submitting a form, fetching images, fetching additional information, and so on. This all works great .... as long as you only access one tool at a time. For example, if I go to test.domain.com/tool-one in one tab, then open test.domain.com/tool-two in another tab, and then go back to tool-one to submit a form, the connection has switched to tool-two and the form submission fails. I had originally called "disable event" at the end of the rule (right after where the elseif is now), which of course prevented you from even accessing another tool while the connection to the first tool persisted. I did suspect this might be the case, but at the time I'd written the iRule we had only one tool stood up on the VMs that are behind the F5. We got a second tool stood up on the VMs behind the F5 yesterday afternoon and I got to do some more testing when i came in this morning.
So the question is how do I use the same domain to access multiple tools without borking up the connections for each tool when a user wants to use multiple tools? Hopefully I've phrased that question correctly and, if not, then hopefully the information provided will give enough context to sort things out.
- Simon_Blakely
Employee
Try applying a oneconnect profile to the virtual server.
What sort of persistence profile are you using?
- cdsmimth
Altostratus
I was using sticky persistence, but I have since switched to no persistence. I'll look up what a oneconnect profile is and try that.
- cdsmimth
Altostratus
The oneconnect profile did not make a difference. I tried it with and without sticky persistence.
- Simon_Blakely
Employee
Define what you mean by sticky persistence?
That isn't an F5 persistence type ...
Use Cookie Persistence. Use something based on the default cookie persistence, and do not specify the cookie name (the cookie name identifies the pool - if you use a custom name, you lose the pool name information and all your pools look alike). You will have a separate cookie for each pool.
The oneconnect profile allows server-side connection reuse, which can be more efficient. However, it also detaches the server-side connection from the client-side connection after every HTTP request/respond event.
This means that a new load-balancing decision is made per request.
You may have a logical error in your irule as well - I'd ensure that any path through the HTTP_REQUEST rule assigns the correct pool for the request with a pool command.
- cdsmimth
Altostratus
We got this sorted out yesterday afternoon. Turns out there was a route in one of our two tools that was not correctly set up. Once we made that change, everything is working as we expected. Thank you to everyone who took the time to read this and extra thanks to for taking the time to respond with a possible solution. I really appreciate it!
- TimRiker
Cirrocumulus
We use an iRule and a datagroup to route different host/[path] to pools in the same iRule. Here's some example code:
set log(search) $host[string tolower [HTTP::uri]] set pool [class match -value $log(search) starts_with dg_shared.example.com] if { $pool ne ""} { set matched [class match -name $log(search) starts_with dg_shared.example.com] set log(matched) $matched set log(pool) $pool if { $pool starts_with "http" } { # datagroup entry is realy a redirect set log(reason) "redirect" call hsllog log HTTP::respond 307 Connection Close Location $pool Virtual-Name [virtual name] TCP::close event disable return } elseif { [catch { pool $pool } ] } { set log(reason) "Failed to Connect to Pool" call hsllog log call errorpage 404 $log(reason) "https://[HTTP::host][HTTP::uri]" log } } else { call errorpage 404 "No Pool Found" "https://[HTTP::host][HTTP::uri]" log }
this uses starts_with so datagroup entries would look like:
test.example.com/ := https://test.example.com/tool-two test.example.com/tool-one := pool_one test.example.com/tool-two := pool_two
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