iRule Preprocessor

Problem this snippet solves:

The engine works by converting a template (which is a string, or a file) into a TCL script, and then running it. Nearly each line of text encountered will be returned as is. The exception is text between =<% ... %>= which is treated as Tcl code (the eval happens in a safe interp, see Safe Interps). This makes it very flexible and it leaves you freedom of doing what you want, dealing with any data and putting how much code you want in the template.

Also for convenience there is a

<%= ... %>
for spooling output (the proc _defaultSpool takes care of sending the text to the right place; you can change that: see Preprocessor Commands).

How to use this snippet:

Template Syntax

Delimiter/CommandNameDescription
<%
Codethe beginning of a template code block
<%=
Outputthe beginning of a template code block that after it is evaluated by the tcl interpreter will hand the results to a function defined by printCommand option
<@%
Preprocessor Codethe beginning of an options block used to set template options such as printCommand, logCommand
<l%
Default Logging Codethe beginning of a logging code block with the log threshold set to 0
<l[0-9]%
Level Select Logging Codethe beginning of a logging code block with the log threshold set to [0-9]
<l%=
Default Logging Outputthe beginning of a logging code block with the log threshold set to 0 which after it is evaluated by the tcl interpreter will hand the results to a function defined by logCommand option
<l[0-9]%=
Level Select Logging Outputthe beginning of a logging code block with the log threshold set to [0-9] which after it is evaluated by the tcl interpreter will hand the results to a function defined by logCommand option
%>
Close Code/Output Blockends the current block of template code for all types of template code blocks

Template Commands

CommandArgumentsOptionsReturnsExplanation
ipp:import_irule_template
BIG-IP_file_object
none
string
templateHandle
Reads the file referenced by the file object and returns a template handle
ipp::setVar
templateHandle templateVariable value
nonenoneset the
templateVariable
to
"value"
which will be used when
ipp::render
is run
ipp::setLog
templateHandle logLevel
nonenonesets the global log level to a value
0-9
for the template specified by
templateHandle
which will be used when
ipp::render
is run
ipp::disableLog
templateHandle
nonenoneglobally disables template logging statements
ipp::render
templateHandle
none
string
templateResult
renders out the template specified by
templateHandle
with all the information provided by the template and the other various methods mentioned above

Simple example

iRule Code

when HTTP_REQUEST {
    set uri [HTTP::uri]
    if {0} {
         log local0. "You should never see this"
    } elseif {[regexp {*.jpg$} $uri]} {
        pool /Common/test1
    } elseif {[regexp {^test*} $uri]} {
        pool /Common/test2
        log local0. "Sending connection from: [IP::remote_addr] to pool: /Common/test1"
    } else {
        log local0. "No match Found"
}
} 

Template Code

1.  when HTTP_REQUEST {
2.      set uri [HTTP::uri]
3.      
4.      
5.      
6.      
7.      if {0} {
8.           log local0. "You should never see this"
9.  <% foreach row $rows { %>
10. <% foreach {regex pool logEnabled} $row break %>
11.     } elseif {[regexp {<%=$regex%>} $uri]} {
12.         pool <%=$pool%>
13. <% if { $logEnabled {{}} "Yes" } { %>
14.         log local0. "Sending connection from: [IP::remote_addr] to pool: <%=$pool%>"
15. <% } } %>
16.     } else {
17.         log local0. "No match Found"
18.     }
19. }

Line by Line

LineExplainationResult
1a literal lineput =when HTTP_REQUEST {= into
content
2a literal lineput =set uri [HTTP::uri]= into
content
3a log line with a log level threshold equal to 1if logLevel >= 1; then put =log local0. "[HTTP::uri]"= into
content
4a log line with a log level threshold equal to 2if logLevel >= 2; then put =log local0. "Client IP: [IP::client_addr]"= into
content
5a log line with a log level threshold equal to 4if logLevel >= 4; then put =log local0. "Client Port: [TCP::remote_port]"= into
content
6a log line with a log level threshold equal to 3if logLevel >= 3; then put =log local0. "Local IP: [IP::local_addr]"= into
content
7a literal lineput =if {0} {= into
content
8a literal lineput =log local0. "You should never see this"= into
content
9template Codeevaluate =foreach row $rows {=
10template Codeevaluate =foreach {regex pool logEnabled} $row break=
11literal with inline template Output codeput =} elseif {[regexp {[puts $regex]} elseif {[regexp {= where $regex is evaluated within the template scope into
content
12literal with inline template Output codeput =pool [put $pool]= where $pool is evaluated within the template scope into
content
13template Codeevaluate =if { $logEnabled
}} "Yes" } {= 
14literal with inline template Output codeput =log local0. "Sending connection from: [IP::remote_addr] to pool: [puts $pool]"= where $pool is evaluated within the template scope into
content
15template Codeevaluate =} }=
16literal lineput =} else {= into
content
17literal lineput =log local0. "No match Found"= into
content
18literal lineput
} into
content
19literal lineput
} into
content

A few Crucial Notes

the

content
variable is the variable where the rendered result is built up and what is eventually returned to the user as the output of {{ipp::render

Preprocessor Configuration

proc _newLog {args} { 
      global content
      set txt "#[join $args]"
      append content $txt 
}

Versions

ipp.1.2.tcl.zip it works MORE perfectly (as of this writing)

Updated Jun 06, 2023
Version 2.0
No CommentsBe the first to comment