Technical Article

Session Table Control With iRules

In my previous article titled Session Table Exporting With iRules, I posted an example iRule that will allow you to export your session table entries for archival purposes. If you are reading this and have no clue what the session table is, you’ll want to read the series titled “The Table Command” where we walk through all the ins and outs of accessing the session data table.

As I mentioned on a recent podcast, I’ve been planning on adding to that tech tip by including the ability to “import” data back into the session table. Well, this article includes that, and much more…

I started writing the code and found my self asking a bunch of “what-ifs”.

What If…

I could look at the session table data…

I could delete session table entries…

I could add session table entries…

I could delete session tables…

Instead of drawing this out into multiple tech tips, I decided to go ahead and push forward and include it all in this one. Previously Jason wrote the “Restful Access to BIG-IP subtables” article where he build a web service for access into the session tables. This is great for those programmer geeks, but I figured I’d take a different approach by building a full blown GUI to interact with the session table and this turned out to be pretty easy with iRules!

The iRule

The entire application was written in a single iRule. By assigning this iRule to a virtual server, you can now make a web request to “http://virtual_ip/subtables” and you will have access to the application. The virtual server can be a production hosting live applications or a secondary one with no active pools behind it. For all request not going to “/subtables” it will ignore the request and pass control to additional iRules and then on the assigned pool of servers.

The Application

The logic in this iRule is wrapped around an application name defined in the “APPNAME” variable. You can change this to whatever you want, but in my example I’ve used the name of “subtables”. If the URI starts with “/subtables” then the below application logic is processed. Otherwise, the request is allows to continue on to the backend pool.

1: when HTTP_REQUEST {

2: set APPNAME "subtables";

3:

4: set luri [string tolower [HTTP::uri]]

5: set app [getfield $luri "/" 2];

6: set cmd [getfield $luri "/" 3];

7: set tname [URI::decode [getfield [HTTP::uri] "/" 4]];

8: set arg1 [URI::decode [getfield [HTTP::uri] "/" 5]];

9: set arg2 [URI::decode [getfield [HTTP::uri] "/" 6]];

10: set resp "";

11:

12: set send_response 1;

13:

14:if { $app equals $APPNAME } {

15: # Application Logic

16: }

17: }

Command Processing

A little way down in the application logic is the command processor. There are 4 public commands: edit, export, import, and delete. These will be described below. There are also a couple of hidden commands that you will have to dig through the source to look at.

Command: edit

The “edit” command will allow you to view the contents of a subtable. If no table name is specified, a form is generated prompting the user to enter a valid table name. If a table name is supplied that currently doesn’t exist on the system, it will act like a create method allowing you to create a new subtable. After that request is made, the else logic is processed and the edit table is presented along with “X” links after each record to allow you to delete that record, and a final row of edit boxes allowing you to insert a new record into the table.

Command: export

The export command was taken from my previous article on exporting the session table. It essentially iterates through all the keys in the subtable and queries their values inserting them into a comma separated list. The file is then returned via the HTTP::respond command by changing the Content-Type to “text/csv” and specifying a unique file name with the Content-Disposition header.

Command: import

This logic is the opposite action from the export command. For the first request to the app, the form is returned containing the fileinput HTML form input item. The browser will then submit a POST request that has to be parsed out. The HTTP::collect call is made on the entire POST body and processing continues in the HTTP_REQUEST_DATA event.

1:if { $tname eq "" } {

2: append resp $FILEINPUT_FORM;

3: } else {

4: append resp "SUBMITTED FILE...";

5:if { [HTTP::header exists "Content-Length"] } {

6: HTTP::collect [HTTP::header "Content-Length"];

7: set send_response 0;

8: }

9: }

Processing the File Upload POST Data

In the previous code block, the HTTP::collect call is made. When the data is buffered up, the HTTP_REQUEST_DATA event is triggered and we can perform the input. I included some validation in here to make sure this is for the current application request and the import command was requested. The Payload is then parsed into lines and the parsing fun begins.

First, let’s look at the post request and then hopefully the iRule logic will make more sense. First we have the “Content-Type” header that contains the boundary for the various form elements. Once we’ve got past all the headers (indicated by the first empty line), I’ll build a little state engine where I set whether I’m “in” or “out” of a boundary. From within the boundary, I check the Content-Disposition for the “filedata” parameter. This logic is then looped through until we get to the contents (again delimited by an empty line after the part headers. Each of those lines are then parsed and the “Table”, “Key”, and “Value” is extracted and the associated “table set” command is called to insert the value into the specified table.

When the processing is complete, a status message is sent to the client indicating the number of records added.