Forum Discussion
Scheduled Maintenance Window
I'm trying to create a rule to return a maintenance page every Saturday morning between 0200 and 0600. I have copied a few examples from DevCentral which work great except for any period of time that includes an 08 or 09. The log entries clearly indicate that it's having an issue with non-octal numbers being returned but I can't figure out how to get around it. I'm betting it's something hugely simple. Suggestions welcomed. Here's the rule as it's written now and the error that is received at 0208, 0209, 0308, 0309,08xx, 09xx etc. Thanks in advance.
when HTTP_REQUEST {
Change the following to set schedule
set start_time "0200";
set end_time "0600";
set day "Saturday";
set l [split [clock format [clock seconds] -format {%A %H %M}] " "]
set cur_day [lindex $l 0]
set cur_time [expr [expr {[lindex $l 1] *100}] + [lindex $l 2]]
if { ($cur_day eq $day) &&
($cur_time >= $start_time) &&
($cur_time <= $end_time) } {
HTTP::respond ----text here----
TCL error: m-window-test HTTP_REQUEST - cant use invalid octal number as operand of * while executing expr {[lindex $l 1] *100}
Also receive this error:
TCL error: m-window-test HTTP_REQUEST - expected integer but got 08 looks like invalid octal number while executing expr [expr {[lindex $l 1] *100}] + [lindex $l 2]]
29 Replies
- hoolio
Cirrostratus
When you use 'clock format' using %k (without the leading zero for the hour field) it pads single digit hours with a space. This extra space generates an empty list element when passed to split and causes the TCL error about a null length string.
Rule snippet showing the problem:log local0. "Clock output: [clock format [clock seconds] -format {%A %k %M}], \$k: $k" set k [split [clock format [clock seconds] -format {%A %k %M}] " "] log local0. "\$k split output llength: [llength $k]"
Log output:
Clock output: Thursday 9 05, $k: Thursday {} 9 05
$k split output llength: 4
Rule snippet:log local0. "Clock output: [clock format [clock seconds] -format {%A %H %M}], \$H: $H" set H [split [clock format [clock seconds] -format {%A %H %M}] " "] log local0. "\$H split output llength: [llength $H]"
Log output:
Clock output: Thursday 09 05, $H: Thursday 09 05
$H split output llength: 3
You can work around this by using scan to parse the day, hour and minute regardless of the spaces:Get time in seconds, formatted as day of week (%A) hour (%k) minute (%M) Use scan to save output as $cur_day $cur_hour $cur_minute scan [clock format [clock seconds] -format {%A %k %M}] {%s %d %d} cur_day cur_hour cur_minute set cur_time ${cur_hour}${cur_minute}
So this example should work. In a simple test if the cur_time is 600 the comparison 600 >= 0600 is true. Though I haven't tested the rule completely.when HTTP_REQUEST { Change the following to set schedule set maintenance_start_time "0200"; set maintenance_end_time "0600"; set maintenance_day "Saturday"; Get time in seconds, formatted as day of week (%A) hour (%k) minute (%M) Use scan to save output as $cur_day $cur_hour $cur_minute scan [clock format [clock seconds] -format {%A %k %M}] {%s %d %d} cur_day cur_hour cur_minute set cur_time ${cur_hour}${cur_minute} log local0. "\$cur_day: $cur_day, \$cur_hour: $cur_hour, \$cur_minute: $cur_minute, \$cur_time: $cur_time" if { ($cur_day eq $maintenance_day) && ($cur_time >= $maintenance_start_time) && ($cur_time <= $maintenance_end_time) } { HTTP::respond "Maintenance message" log local0. "Maintenance message" } }
Aaron - Tim_Moomaw_9220
Nimbostratus
Aaron,
With a little tweaking to get the "0"s to pass correctly to the variables, the following is working correctly now for all times that I have attempted, including midnight to 1:00am.
when HTTP_REQUEST {
Change the following to set schedule
set maintenance_start_time "200";
set maintenance_end_time "615";
set maintenance_day "Saturday";
Get time in seconds, formatted as day of week (%A) hour (%k) minute (%M)
Use scan to save output as $cur_day $cur_hour $cur_minute
scan [clock format [clock seconds] -format {%A %k %M}] {%s %s %s} cur_day cur_hour cur_minute
set cur_time ${cur_hour}${cur_minute}
log local0. "\$cur_day: $cur_day, \$cur_hour: $cur_hour, \$cur_minute: $cur_minute, \$cur_time: $cur_time"
if { ($cur_day eq $maintenance_day) &&
($cur_time >= $maintenance_start_time) &&
($cur_time <= $maintenance_end_time) } {
HTTP::respond 200 content " Site Maintenance
text=800517>
Site is temporarily unavailable.Site will be available again at 6:15am.
We are sorry for any inconvenience. "
}
}
Thanks very much to all who responded. - hoolio
Cirrostratus
Hi Tim,
Thanks for posting your tested solution.
When you say you had to tweak the 0's do you mean you had to trim the leading zeros from the start and end times in RULE_INIT?
Aaron - Tim_Moomaw_9220
Nimbostratus
Original:
scan [clock format [clock seconds] -format {%A %k %M}] {%s %d %d} cur_day cur_hour cur_minute
Now:
scan [clock format [clock seconds] -format {%A %k %M}] {%s %s %s} cur_day cur_hour cur_minute
The %d in the "minutes" variable was stripping the 0 off of it. 6:05am became 65, etc. I'm not sure if the %s in the hour field made a difference or not since %k is only passing 1 digit prior to 12:00pm anyway. I should have tested that at midnight as well.... - Johan_47487
Nimbostratus
Thank you for your help,
Here a modified version, with a forward to another virtual server :)
when HTTP_REQUEST {
set start "10/03 18:00"
set end "11/03 07:00"
scan [clock format [clock seconds] -format {%m %d %k %M}] {%d %s %s %s} cur_month cur_day cur_hour cur_minute
scan $start {%d/%d %d:%d} start_day start_month start_hour start_minute
scan $end {%d/%d %d:%d} end_day end_month end_hour end_minute
set start [expr (${start_month}000000 + ${start_day}0000 + ${start_hour}00 + ${start_minute} )]
set end [expr (${end_month}000000 + ${end_day}0000 + ${end_hour}00 + ${end_minute} )]
set cur_time ${cur_month}${cur_day}${cur_hour}${cur_minute}
if { $cur_time >= $start and $cur_time < $end} {
set url [string tolower "[HTTP::host][HTTP::uri]"]
if {[matchclass unavailable starts_with [HTTP::host]]} {
foreach value [class match -value $url starts_with unavailable] {
set newuri $value
}
if {not [matchclass [HTTP::uri] equals f5_custom_pages]} {
HTTP::uri $newuri
}
virtual F5_CUSTOMS
}
}
} - hoolio
Cirrostratus
Hi Johan,
Thanks for posting your update.
You could make that a bit more efficient by setting the start and end variables in RULE_INIT as static variables (in v10). You could also save a few cycles by wrapping the expr operands in curly braces:
set start [expr (${start_month}000000 + ${start_day}0000 + ${start_hour}00 + ${start_minute} )]
set end [expr (${end_month}000000 + ${end_day}0000 + ${end_hour}00 + ${end_minute} )]
->
set start [expr {${start_month}000000 + ${start_day}0000 + ${start_hour}00 + ${start_minute} }]
set end [expr {${end_month}000000 + ${end_day}0000 + ${end_hour}00 + ${end_minute} }]
Also, if you're on 10.x, it would be more efficient to replace matchclass with 'class match'.
Aaron - Jonathan_H_4580
Nimbostratus
Hi,
I need to be able to specify a calendar date and time for my maintenance window rather than a recurring day of the week. To do this I have attempted to use the iRule that Johan suggested above on 3/10/2011. I modified it slightly so that a particular pool will be used during my maintenance window -- see below for my rule. HOWEVER, when I test the rule it fails to take effect!!! Any suggestions would be much appreciated.
Thanks, Jonathan
Note syntax is "date/month hour:minute"; and hour should NOT start with zero.
when HTTP_REQUEST {
set start "29/5 18:45"
set end "29/5 18:50"
scan [clock format [clock seconds] -format {%m %d %k %M}] {%d %s %s %s} cur_month cur_day cur_hour cur_minute
scan $start {%d/%d %d:%d} start_day start_month start_hour start_minute
scan $end {%d/%d %d:%d} end_day end_month end_hour end_minute
set start {expr (${start_month}000000 + ${start_day}0000 + ${start_hour}00 + ${start_minute} )}
set end {expr (${end_month}000000 + ${end_day}0000 + ${end_hour}00 + ${end_minute} )}
set cur_time ${cur_month}${cur_day}${cur_hour}${cur_minute}
if { $cur_time >= $start and $cur_time < $end} {
pool MAINT-POOL
}
} - hoolio
Cirrostratus
Hi Jonathan,
I think it would be simpler and more efficient to convert the start and end datestamps to seconds since the Unix epoch once at rule save. You could then avoid a lot of the parsing with an iRule like this (untested):when RULE_INIT { Start of maintenance window in YYYY-mm-dd HH:MM format set static::start_date "2011-05-29 18:45" End of maintenance window in YYYY-mm-dd HH:MM format set static::end_date "2011-05-29 18:50" Convert start/end times to seconds from the epoch for easier date comparisons set static::start [clock scan $static::start_date] set static::end [clock scan $static::end_date] } when CLIENT_ACCEPTED { Save the current time in seconds since the epoch set now [clock seconds] Use the maintenance pool if we're in the maintenance window if {$now > $static::start and $now < $static::end}{ pool MAINT-POOL } }If you're on v9, you'd want to change the static variables to global variables by removing "static" from the variable references. This assumes you don't need CMP compatibility. If you do, then you could move the variable declarations from RULE_INIT to CLIENT_ACCEPTED or add them to the session table using the session command.
Aaron - Jonathan_H_4580
Nimbostratus
Thanks very much for the quick response Aaron, I will give that a try. I'm running 10.0.1 on an F5 1600, so would the iRule you suggested be appropriate as shown? I'm unsure whether CMP considerations might be relevant, or if so, how the iRule might be adjusted. Thanks again!
Jonathan - hoolio
Cirrostratus
For any 10.x version the iRule I posted will work and maintain CMP compatibility (http://devcentral.f5.com/Community/GroupDetails/tabid/1082223/asg/50/aft/29608/showtab/groupforums/Default.aspx1250581).
Aaron
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com