Assigning iFile to a variable in RULE_INIT
Problem this snippet solves:
When iFile is used inside RULE_INIT to define a variable, the variable is not defined when referenced later inside other events. This happens when the F5 BIG-IP is rebooted.
According to F5 Support, this is currently (BIG-IP v12.1.2) a known issue with no fix.
Proof of concept:
Assuming that the iFile
default_maintenance.html_ifile
has already been created, the following example is trying to assign the iFile to a variable, which is later used as the "HTTP 503" maintenance page (when there's no active node left in the pool).
when RULE_INIT priority 100 { # Default Maintenance page for all HTTP based VIPs # set static::default_maintenance_page [ifile get default_maintenance.html_ifile] } when HTTP_REQUEST priority 900 { # Selected pool is down # if { [active_members [LB::server pool]] < 1 } { HTTP::respond 503 -version auto content $static::default_maintenance_page noserver "Content-Type" "text/html" "Cache-Control" "no-cache" "Retry-After" "60" "Connection" "Close" event disable return } }
This code works well when the iRule is created, because that's when the RULE_INIT event is triggered and iFile already exists. However, if the BIG-IP is rebooted, the code fails with an error in LTM log:
Jun 8 20:32:36 BIGIP err tmm3[20247]: 01220001:3: TCL error: /Common/default_baseline-http_irule <RULE_INIT> - iFile default_maintenance.html_ifile not found (line 1) invoked from within "ifile get default_maintenance.html_ifile"
because iRules get initialized before iFiles are loaded.
If the pool is down, any attempt to talk to that virtual will end up with a connection failure and an error in LTM log:
Jun 8 20:34:50 BIGIP err tmm3[20247]: 01220001:3: TCL error: /Common/default_baseline-http_irule <HTTP_REQUEST> - can't read "static::default_maintenance_page": no such variable while executing "HTTP::respond 503 -version auto content $static::default_maintenance_page noserver "Content-Type" "text/html" "Cache-Control" "no-cache" "Retry-After"..."
At this point, the only way to fix this is by re-opening the iRule and clicking the Update button to trigger the iRule re-initialization.
How to use this snippet:
The following workaround is using "after" command to create a non-blocking loop to check whether the iFile already exists.
If it does exist, the "after" script loads and assigns the iFile to a variable, and cancels the loop. If it doesn't exist, the "after" script continues in its non-blocking loop, until it detects that the iFile exists.
Code :
when RULE_INIT priority 100 { # Check every second in a non-blocking loop whether iFile exists: # # - if YES: load and assign the iFile to a variable, and cancel the loop # - if NO: continue in the non-blocking loop # # This is a workaround for Bug #426220: # # When iFile is used inside rule_init to define variable, the variable is not defined # when referenced later inside other events # # This should give the iFile a chance to get loaded after a reboot, before the iRule starts # referencing it, but load and assign it ASAP (1s delay), if the iRule is created or updated # via CLI or F5 management web interface. # after 1000 -periodic { if { [lsearch -glob [ifile listall] "*/default_maintenance.html_ifile"] != -1 } { # Default Maintenance page for all HTTP based VIPs # set static::default_maintenance_page [ifile get default_maintenance.html_ifile] log local0. "default_maintenance.html_ifile loaded and assigned" after cancel -current } } } when HTTP_REQUEST priority 900 { # Selected pool is down # if { [active_members [LB::server pool]] < 1 } { HTTP::respond 503 -version auto content $static::default_maintenance_page noserver "Content-Type" "text/html" "Cache-Control" "no-cache" "Retry-After" "60" "Connection" "Close" event disable return } }
Tested this on version:
12.1