Forum Discussion

Chad_Roberts_21's avatar
Chad_Roberts_21
Icon for Nimbostratus rankNimbostratus
May 16, 2006

Time-based iRules

I hope this question is unique enough to be worthy of a new post. Unfortunately, searching for the word "time" with various other keywords didn't appear to be specific enough to find my anything of interest, so here goes...

 

 

Is it possible to use time as a factor in iRules? I'd like to direct traffic to one pool during normal business hours and to another pool after hours, but I haven't been able to find any command or variable that gives me this ability. If no one knows of a way to do it with iRules, does anyone know any other way to do it within the configuration of version 9?

 

 

Thanks for the look.

8 Replies

  • absolutely! You can use the TCL clock command to get the current time.

     

     

    http://tmml.sourceforge.net/doc/tcl/clock.html

     

     

    This will set a variable to record the current hour and minute:

     

     

    set time_current [clock format [clock seconds] -format {%H:%M}]

     

     

    9.2 fixed a performance issue with using the clock command. You can probably find the post by searching for clock.

     

     

  • Awesome! Thanks, I'll give it a try. I've gone through all kinds of stuff on iRules, but I have a lot to learn on TCL in general.
  • Does anyone have an example of a complete iRule that chooses an action based on time? I understand better now how setting a variable to clock time is done, but I've been experimenting for the last couple of hours to determine how to write expressions using this number. For example, if I want PoolA to be used between 08:00 and 17:00 (normal business hours) and PoolB to be used during any other hours, how might the expression be written so that current time is compared to those times?

     

     

    Thanks!
  • Nevermind my last request. Given enough time and caffeine, anything is possible. In case anyone in the future would like to accomplish a similar task, here is the code I used:

     

     

    when HTTP_REQUEST {
    set current_day [clock format [clock seconds] -format {%a} ]
    set current_time [clock seconds]
    set time_min [clock scan {08:00}]
    set time_max [clock scan {17:00}]
    if {($current_day == {Sat}) or ($current_day == {Sun})} {
    pool after_hours_pool
    }
    elseif {($current_time < $time_min) or ($current_time > $time_max)} {
    pool after_hours_pool
    }
    }

     

     

    Note that my goal was to send traffic to an after-hours server on weekends, before 8 AM, and after 5 PM. Because I did not specify an "else", traffic that does not match these requests passes through the iRule unaffected and is acted upon as though the iRule does not exist at all.
  • I'd recommend moving this to the CLIENT_ACCEPTED event unless you have a specific need to move existing client sessions to the other pool during your on/off hour transitions.
  • Hmm, good call. Using HTTP_REQUEST instead of CLIENT_ACCEPTED would probably have some impact on performance as well, would it not?
  • Actually, that does present a new issue. I showed a simple version of my iRule yesterday because the rest of what I've actually used was not relevant to the conversation at hand, but the full code I used doesn't check out when I try to change it to CLIENT_ACCEPTED.

     

     

    The particular virtual server for which this iRule was created hosts multiple domains, and not all of them should be unavailable after hours. As a result, I need to be able to check the host name for one and the path for another, send those to an after-hours pool, and allow the rest through as normally planned. Also, for reasons I won't get into, I have to rewrite the uri so that the path is only "/" when it hits the after-hours pool.

     

     

    when HTTP_REQUEST {
    set current_day [clock format [clock seconds] -format {%a} ]
    set current_time [clock seconds]
    set time_min [clock scan {08:00}]
    set time_max [clock scan {17:00}]
    set uri [HTTP::uri]
    if { ([HTTP::host] eq "www.domain.com") or ([HTTP::uri] contains "/folder") } {
    if {($current_day == {Sat}) or ($current_day == {Sun})} {
    HTTP::uri "/"
    pool test_clock_pool
    }
    elseif {($current_time < $time_min) or ($current_time > $time_max)} {
    HTTP::uri "/"
    pool test_clock_pool
    }
    }
    }

     

     

    When I attempt to change it to CLIENT_ACCEPTED, I receive the following error:

     

     

    01070151:3: Rule [irule_test_SC_business_hours] error:

     

    line 6: [command is not valid in current event context (CLIENT_ACCEPTED)] [HTTP::uri]

     

    line 8: [command is not valid in current event context (CLIENT_ACCEPTED)] [HTTP::host]
  • You could set your clock variables in the CLIENT_ACCEPTED event so they are only set once. If you are not using your uri variable, I wouldn't set it. If it is necessary, that variable will need to remain in the HTTP events.

    There will be a performance hit for setting those variables each time, though I'm unsure if it would be noticeable. You can turn timing on to evaluate.

    Details on how to configure it:

    Posted By unRuleY on 3/22/2005 4:19 PM

    That is a very good point. You have obviously thought about this. Of course, it will all really depend on just how often you expect to match. If it does not match often, then you are completely correct. If it matches regularly, then you would likely want to save the result in a variable. Another factor to weigh is the number of elements in the class/datagroup.

    For those that are interested and paying attention, I'm now going to mention a YASF (yet another stealth feature):

    You can enable timing statistics in a rule which will allow you to see just how many cycles are spent evaluating a given rule event. The way you do this is with the "timing on" statement.

    An example that enables timing for all subsequent events in a rule is:

       
     rule my_fast_rule {   
        timing on   
        when HTTP_REQUEST {   
            Do some stuff   
        }   
     }   
     

    An example of only timing a specific event is:

       
     rule my_slow_rule {   
        when HTTP_REQUEST timing on {   
            Do some other stuff   
        }   
     }   
     

    This will then collect timing information each time the rule is evaluated and can be viewed with "b rule show all". You'll likely only want to look at the average and min numbers as max is often way, way out there due to the optimizations being performed on the first run of the rule. Additionally, enabling timing does have some overhead, though it should be negligible.

    Details on how to make sense of the numbers:

    http://devcentral.f5.com/Default.aspx?tabid=28&view=topic&forumid=5&postid=3650