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
Updated Jun 06, 2023
Version 2.0
No CommentsBe the first to comment