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
- 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'...
tmm in the above log has the correct value, but tmm2 has the incorrect value...
Is this a process sync issue? - 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...
I'm thinking of re-working it slightly, so that instead of a day, start time and end time being passed in, only a start date-time and duration is required...
However I'm having some issues getting a string converted into a valid DT object...
"Clock scan" looks like the most appropriate, but it doesn't appear possible to specify a format option...
Any pointers?
Cheers
Gavin - GavinW_29074
Nimbostratus
OK, looks like I've managed to get a workable solution in place...
Below is the code that I've created. Thought I'd post it here for comment before submitting to Code Share.
Cheers
Gavinwhen 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.
See the CMP page for details:
http://devcentral.f5.com/wiki/iRules.CMPCompatibility.ashx
Aaron - 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...
Spark, you're right that it never gets read in this rule. However its the first thing to be read in the other rules... will post some sample code up later...
Gav - GavinW_29074
Nimbostratus
Ok, I've gone back and simplified the rule so that it can be easily checked from other rules...
New rule looks like:
Edit: Posted in next reply as formatting when strange...
The framework for other rules to check for the maintenance window is: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... } }
Again, comments welcome...
I'll also look at getting this submitted to Code Share at some point over the next couple of days.
Regards
Gavin - 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...
Link is: http://devcentral.f5.com/wiki/iRules.LTM-Dynamic-Maintenance-using-Session-Table.ashx?NoRedirect=1&NS=iRules
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