Forum Discussion
GavinW_29074
Nimbostratus
Nov 04, 2011Stats Profile funnies...
Hi there,
I'm trying to implement an iRule for a dyncamic maintenance page using the following iRule: http://devcentral.f5.com/wiki/iRules.LTMMaintenanceWindow.ashx
However I'm having some weird issues with the stats profile...
It's almost like the stats profile is being stored differently for different sessions?!
Is this possible???
E.g. the following is a log extract from the above iRule... I've put in some additional logging to output the current values stored for the start and end times...
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $day: 5, $start_time: 940, $end_time: 950
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time less than 4 characters
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time now 0940
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $cur_day: 5, $cur_time: 1224
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
Nov 4 12:24:15 tmm info tmm[6377]: Rule /Common/MaintenancePage : $day: 5, $start_time: 1220, $end_time: 1300
Nov 4 12:24:15 tmm info tmm[6377]: Rule /Common/MaintenancePage : $cur_day: 5, $cur_time: 1224
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $day: 5, $start_time: 940, $end_time: 950
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time less than 4 characters
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time now 0940
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $cur_day: 5, $cur_time: 1224
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $day: 5, $start_time: 940, $end_time: 950
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time less than 4 characters
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time now 0940
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $cur_day: 5, $cur_time: 1224
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $day: 5, $start_time: 940, $end_time: 950
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time less than 4 characters
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $start_time now 0940
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/MaintenancePage : $cur_day: 5, $cur_time: 1224
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
Nov 4 12:24:15 tmm2 info tmm2[6379]: Rule /Common/splunk_http : Sending log to Splunk...
As you can see from the above, some lines have a start_time and end_time of 940/950, and some have 1220/1300... 1220/1300 is the last value i've set...
Any ideas???
Cheers
Gavin
10 Replies
Sort By
- GavinW_29074
Nimbostratus
Hmm, might be something or noting... But, i've had a closer look at the logs, and I can see that the different times being returned and being returned by different 'tmm' process'... - spark_86682Historic F5 AccountEach TMM only has read access to its own values for STATS profiles. Only processes outside of tmm (like tmsh, for instance) have access to combined stats across all TMMs. It is possible that that iRule was written when all or most systems only had one TMM. My suggestion is to use the session table (by using the table iRule command) in place of the STATS:: commands.
- GavinW_29074
Nimbostratus
Ok, looks like I'm rewriting the rule to use the session table then... - GavinW_29074
Nimbostratus
OK, looks like I've managed to get a workable solution in place...when RULE_INIT { set static::SUBTABLE "maintenance_window" set static::debug 1 Global variable to use within other iRules to prevent multiple invocation errors. set ::MAINTENANCE_MODE 0 } when HTTP_REQUEST priority 10 { set VS_NAME [virtual name] set TITLE "[substr $VS_NAME 8] iRule Maintenance Window Control" set PROFILE [substr $VS_NAME 8] set PROFILE_NAME [concat [string map {. _} $PROFILE]_maintenance_window] if {$static::debug == 1} { log local0.info "VS Name: $VS_NAME Title: $TITLE Profile: $PROFILE Profile Name: $PROFILE_NAME" } Look for embedded commands to control the maintenance window. switch -glob [string tolower [HTTP::uri]] { "/enable*" { Extract the maintenance window day, start date time, and duration from the URI. If not there, return an error message. set params [split [HTTP::uri] "/"] if { [llength $params] < 4 } { HTTP::respond 200 content " $TITLE Usage: http://[HTTP::host]/enable/start_date_time/duration Start Date Time must be of the format yyyy-mm-dd hh24:mi:ss Duration is in Hours " } else { Assign the values to variables. set START_VALUE [string map {"%20" " "} [lindex $params 2] ] set DURATION_HOURS [lindex $params 3] if {$static::debug == 1} { log local0.info "Start Value = $START_VALUE, Duration = $DURATION_HOURS." } Process input set START_EPOCH [clock scan $START_VALUE ] if {$static::debug == 1} { log local0.info "Start EPOCH = $START_EPOCH" } set DURATION_SECS [expr {$DURATION_HOURS*60*60}] if {$static::debug == 1} { log local0.info "Duration = $DURATION_SECS" } Add value to subtables table set -subtable $static::SUBTABLE $PROFILE_NAME $START_EPOCH 0 $DURATION_SECS HTTP::respond 200 content " $TITLE Maintenance Window enabled " } } "/disable" { By removing the session table entries, the maintenance is removed. if {$static::debug == 1} { log local0.info "Removing set Maintenance window..." } table delete -subtable $static::SUBTABLE $PROFILE_NAME HTTP::respond 200 content " $TITLE Maintenance Window disabled " } "/check" { Return the current time and the current settings for the maintenance window set START_EPOCH [table lookup -subtable $static::SUBTABLE $PROFILE_NAME] Set Common variables. set NOW_EPOCH [clock seconds] set NOW_DTS [clock format $NOW_EPOCH ] if { $START_EPOCH != "" } { set START_DTS [clock format $START_EPOCH] set DURATION [table lifetime -subtable $static::SUBTABLE $PROFILE_NAME] set DIFFERENCE [expr { $NOW_EPOCH - $START_EPOCH } ] set RESPONSE "$START_DTS for [expr {$DURATION/60/60}] hours" Debug Logging if {$static::debug == 1} { log local0.info "Maintenance window set..." log local0.info "Table values: Start EPOCH - $START_EPOCH Duration - $DURATION" log local0.info "Start DTS = $START_DTS Date Time now = $NOW_EPOCH" log local0.info "Difference = $DIFFERENCE" } } else { set START_DTS "No Maintenance Window set" set RESPONSE $START_DTS Debug Logging if {$static::debug == 1} { log local0.info "No Maintenance Window set..." } } HTTP::respond 200 content " $TITLE Current Date and time: $NOW_DTS Maintenance Window: $RESPONSE " } "/usage" { Usage instructions for the commands HTTP::respond 200 content " $TITLE Usage: http://[HTTP::host]/\[command\] /enable/start_date_time(yyyy-mm-dd hh24:mm:ss)/duration(h) - enable maintenance window. /disable - disable maintenance window. /check - check if in maintenance window. /usage - display this usage message " } default { no secret command entered, so check the maintenance window Get the values from the statistics profile. set START_EPOCH [table lookup -subtable $static::SUBTABLE $PROFILE_NAME] set DURATION [table lifetime -subtable $static::SUBTABLE $PROFILE_NAME] Debug logging if {$static::debug == 1} { log local0.info "Table values: Start EPOCH - $START_EPOCH Duration - $DURATION" } Check if start_epoch is non-null. if { $START_EPOCH != "" } { Use the TCL "clock" command to get the current time as epoch. set NOW_EPOCH [clock seconds] if {$static::debug == 1} { log local0.info "Current EPOCH Time = $NOW_EPOCH" } Check NOW against Scheduled start if { $NOW_EPOCH < $START_EPOCH } { Not yet in maintenance, therefore return for other processing return } else { Now must be greater than Start Epoch value, therefore in maintenance or after maintenance set DIFFERENCE [expr { $NOW_EPOCH - $START_EPOCH } ] if {$static::debug == 1} { log local0.info "Difference between Now and Start Epoch is $DIFFERENCE" } if { $DIFFERENCE < $DURATION } { Within maintenance window if {$static::debug == 1} { log local0.info "In Maintenance window - Returning holding page." } if { [HTTP::uri] ends_with "logo-act.png" } { if {$static::debug == 1} { log local0.info "Returning Logo..." } HTTP::respond 200 content [b64decode [class element -value 0 act_logo_png]] "Content-Type" "image/png" } else { if {$static::debug == 1} { log local0.info "Returning html..." } HTTP::respond 200 content [class element -value 0 offline_page_html] "Content-Type" "text/html" } Set Maintenance mode global variable. set ::MAINTENANCE_MODE 1 } elseif { $DIFFERENCE > $DURATION } { Outside of Maintenance window if {$static::debug == 1} { log local0.info "Outside of Maintenance window. Unsetting Maintenance Mode." } Unset maintenance mode flag for good measure set ::MAINTENANCE_MODE 0 Remove session table entry. table delete -subtable $static::SUBTABLE $PROFILE_NAME } } } else { Not in maintenance window, so allow connection to continue to application. if {$static::debug == 1} { log local0.info "Not In Maintenance window - Continuing." } Ensure Maintenance Mode global variable is unset. set ::MAINTENANCE_MODE 0 } } } }
- hoolio
Cirrostratus
I haven't read through the whole rule, but one simple optimization would be to use a subtable instead of a global variable for maintenance_mode. A subtable will be CMP compatible whereas a global variable will pin the iRule to running only on the first TMM instance. - spark_86682Historic F5 AccountThe ::MAINTENANCE_MODE variable appears to never actually be read, only written to. I think it can be removed entirely. But that looks like a pretty good adaptation of that iRule! Nice job!
- GavinW_29074
Nimbostratus
Hoolio, cheers for the pointer. Will see if I can work up a very simple check for the other rules to use... - GavinW_29074
Nimbostratus
Ok, I've gone back and simplified the rule so that it can be easily checked from other rules...when RULE_INIT { Debug set static::debug 1 set static::MAINTENANCE "maintenance_window" } when HTTP_REQUEST priority 300 { if { [table lookup -subtable $static::MAINTENANCE [virtual name]] != "" } { In Maintenance mode. Log and return. if { $static::debug == 1 } {log local0.info "In Maintenance mode. Returning..." } return } else { Not in Maintenance mode. Continuing... if { $static::debug == 1 } {log local0.info "Not In Maintenance mode. Continuing..." } Do stuff here... } }
- GavinW_29074
Nimbostratus
iRule:when RULE_INIT { set static::SUBTABLE "maintenance_window" set static::debug 1 } when HTTP_REQUEST priority 10 { set VS_NAME [virtual name] set TITLE "[substr $VS_NAME 8] iRule Maintenance Window Control" if {$static::debug == 1} { log local0.info "VS Name: $VS_NAME Title: $TITLE" } Look for embedded commands to control the maintenance window. switch -glob [string tolower [HTTP::uri]] { "/enable*" { Extract the maintenance window day, start date time, and duration from the URI. If not there, return an error message. set params [split [HTTP::uri] "/"] if { [llength $params] < 4 } { HTTP::respond 200 content " $TITLE Usage: http://[HTTP::host]/enable/start_date_time/duration Start Date Time must be of the format yyyy-mm-dd hh24:mi:ss Duration is in Hours " } else { Assign the values to variables. set START_VALUE [string map {"%20" " "} [lindex $params 2] ] set DURATION_HOURS [lindex $params 3] if {$static::debug == 1} { log local0.info "Start Value = $START_VALUE, Duration = $DURATION_HOURS." } Process input set START_EPOCH [clock scan $START_VALUE ] if {$static::debug == 1} { log local0.info "Start EPOCH = $START_EPOCH" } set DURATION_SECS [expr {$DURATION_HOURS*60*60}] if {$static::debug == 1} { log local0.info "Duration = $DURATION_SECS" } Add value to subtables table set -subtable $static::SUBTABLE $VS_NAME $START_EPOCH 0 $DURATION_SECS HTTP::respond 200 content " $TITLE Maintenance Window enabled " } } "/disable" { By removing the session table entries, the maintenance is removed. if {$static::debug == 1} { log local0.info "Removing set Maintenance window..." } table delete -subtable $static::SUBTABLE $VS_NAME HTTP::respond 200 content " $TITLE Maintenance Window disabled " } "/check" { Return the current time and the current settings for the maintenance window set START_EPOCH [table lookup -subtable $static::SUBTABLE $VS_NAME] Set Common variables. set NOW_EPOCH [clock seconds] set NOW_DTS [clock format $NOW_EPOCH ] if { $START_EPOCH != "" } { set START_DTS [clock format $START_EPOCH] set DURATION [table lifetime -subtable $static::SUBTABLE $VS_NAME] set DIFFERENCE [expr { $NOW_EPOCH - $START_EPOCH } ] set RESPONSE "$START_DTS for [expr {$DURATION/60/60}] hours" Debug Logging if {$static::debug == 1} { log local0.info "Maintenance window set..." log local0.info "Table values: Start EPOCH - $START_EPOCH Duration - $DURATION" log local0.info "Start DTS = $START_DTS Date Time now = $NOW_EPOCH" log local0.info "Difference = $DIFFERENCE" } } else { set START_DTS "No Maintenance Window set" set RESPONSE $START_DTS Debug Logging if {$static::debug == 1} { log local0.info "No Maintenance Window set..." } } HTTP::respond 200 content " $TITLE Current Date and time: $NOW_DTS Maintenance Window: $RESPONSE " } "/usage" { Usage instructions for the commands HTTP::respond 200 content " $TITLE Usage: http://[HTTP::host]/\[command\] /enable/start_date_time(yyyy-mm-dd hh24:mm)/duration(h) - enable maintenance window. /disable - disable maintenance window. /check - check if in maintenance window. /usage - display this usage message " } default { no secret command entered, so check the maintenance window Get the values from the relevant session subtable. set START_EPOCH [table lookup -subtable $static::SUBTABLE $VS_NAME] set DURATION [table lifetime -subtable $static::SUBTABLE $VS_NAME] Debug logging if {$static::debug == 1} { log local0.info "Table values: Start EPOCH - $START_EPOCH Duration - $DURATION" } Check if start_epoch is non-null. if { $START_EPOCH != "" } { Use the TCL "clock" command to get the current time as epoch. set NOW_EPOCH [clock seconds] if {$static::debug == 1} { log local0.info "Current EPOCH Time = $NOW_EPOCH" } Check NOW against Scheduled start if { $NOW_EPOCH < $START_EPOCH } { Not yet in maintenance, therefore return for other processing if {$static::debug == 1} { log local0.info "Before scheduled maintenance window. Returning to continue other rules..." } return } else { Now must be greater than Start Epoch value, therefore in maintenance or after maintenance set DIFFERENCE [expr { $NOW_EPOCH - $START_EPOCH } ] if {$static::debug == 1} { log local0.info "Difference between Now and Start Epoch is $DIFFERENCE" } if { $DIFFERENCE <= $DURATION } { Within maintenance window if {$static::debug == 1} { log local0.info "In Maintenance window - Returning holding page." } if { [HTTP::uri] ends_with "logo-act.png" } { if {$static::debug == 1} { log local0.info "Returning Logo..." } HTTP::respond 200 content [b64decode [class element -value 0 act_logo_png]] "Content-Type" "image/png" } else { if {$static::debug == 1} { log local0.info "Returning html..." } HTTP::respond 200 content [class element -value 0 offline_page_html] "Content-Type" "text/html" } } else { Outside of Maintenance window if {$static::debug == 1} { log local0.info "Outside of Maintenance window. Unsetting Maintenance Mode." } Remove session table entry. table delete -subtable $static::SUBTABLE $VS_NAME } } } else { Not in maintenance window, so allow connection to continue to application. if {$static::debug == 1} { log local0.info "Not In Maintenance window - Continuing." } } } } }
- GavinW_29074
Nimbostratus
FYI - Have posted it on CodeShare...
Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects