Pool Member Status HTML5 Page
Problem this snippet solves:
This allows a publicly accessible status page of Pools and Pool Members. No cron job is needed.
How to install:
- If you only have one pool, you will probably have to comment out the "errmsg" HTML response code. For some reason one pool in the Data Group List kicks out an error. "Errmsg" is on lines 60 and 121.
Edits to the code:
- Line 3 - Modify to your IP scheme to lock down access, or allow all
- Line 8 - Document title information (shows in browser tab)
- Line 10 - Author information
- Line 11 - Auto refresh interval (update line 30 if you change this)
- Line 34 - Page title information
- Lines 44-45 - Links to other locations if you have devices in different locations/groups
- Line 122 - Comment out with a "#" if you don't wish to log each time someone connects or the page refreshes
*HTML source and inspiration taken from user The Bhattman and the code is revamped: https://devcentral.f5.com/codeshare/pool-member-status-page-on-a-virtual-server-v10
How to use this snippet:
Screenshot
Code :
when HTTP_REQUEST {
if { [HTTP::uri] eq "/status" } {
set response "<!DOCTYPE html>\r\n"
append response "<html lang=\"en\">\r\n"
append response "<head>\r\n"
append response "<title>F5 LTM Server Pool Status</title>\r\n"
append response "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\r\n"
append response "<meta name=\"author\" content=\"Troy Luschen 16Mar2017\"/>\r\n"
append response "<meta http-equiv=\"refresh\" content=\"30\"/>\r\n"
append response "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\r\n"
# ------ Style Section ------
append response "<style>\r\n"
append response "h1 {font-weight:normal;text-transform:uppercase;color:#000000;background-color:#D9D7DE;border: 5px groove #699635;font-size:100%;text-align:center;font-family:lucida sans unicode, lucida grande, sans-serif;line-height:3;margin:0px;padding:5px;min-width:675px;width:50%;}\r\n"
append response "h2 {font-weight:normal;font-style:italic;color:#000000;letter-spacing:0pt;word-spacing:1pt;border: 0px;font-size:80%;text-align:center;font-family:lucida sans unicode, lucida grande, sans-serif;line-height:1;margin:0px;padding:0px;min-width:675px;width:50%;}\r\n"
append response "h4 {font-weight:bold;color:#000000;letter-spacing:0pt;word-spacing:1pt;border: 0px;font-size:90%;text-align:left;font-family:lucida sans unicode, lucida grande, sans-serif;line-height:1;margin:0px;padding:0px;}\r\n"
append response "div.layout1 {width:50%;padding:5px;min-width:675px;}\r\n"
append response "div.layout2 {width:50%;padding:7px;min-width:675px;font-size:90%;font-family:lucida sans unicode, lucida grande, sans-serif;}\r\n"
append response "p {font-weight:normal;color:#000000;border:0px;font-size:90%;text-align:left;font-family:lucida sans unicode, lucida grande, sans-serif;}\r\n"
append response "p.time {font-weight:normal;color:#000000;letter-spacing:1pt;word-spacing:1pt;font-size:80%;text-align:left;font-family:arial,helvetica,sans-serif;line-height:1;margin:0px;padding:0px;}\r\n"
append response "p.time2 {font-weight:normal;color:#000000;letter-spacing:1pt;word-spacing:1pt;font-size:70%;text-align:left;font-family:arial,helvetica,sans-serif;line-height:1;margin:0px;padding:0px;}\r\n"
append response "li {font-weight:normal;color:#000000;border:0px;font-size:90%;text-align:left;font-family:lucida sans unicode, lucida grande, sans-serif;line-height:1;margin:0px;padding:0px;}\r\n"
append response "#pool_status th {font-weight:bold;padding-top:12px;padding-bottom:12px;text-align:left;background-color:#85c1e9;color:#434474;}\r\n"
append response "#pool_status tr table tr:nth-child(even){background-color:#ddd;}\r\n"
append response "#pool_status tr table tr:hover {font-weight:bold;font-size:110%;font-variant:small-caps;background-color:#B7950B;}\r\n"
append response "</style>\r\n"
# ------ End Style Section ------
append response "</head>\r\n"
append response "<body>\r\n"
append response "<p class=\"time\">Status Check Time: [clock format [clock seconds]]</p>\r\n"
append response "<p class=\"time2\">Auto Refreshes Every 30 Seconds</p>\r\n"
append response "<br>\r\n"
append response "<h1>F5 LTM Server Pool Status</h1>\r\n"
append response "<h2>Status of Virtual Servers and their Pool Members</h2>\r\n"
append response "<br>\r\n"
# Table containing "F5 Locations" and "Critical" sections.
append response "<div class=\"layout1\">\r\n"
append response "<table style=\"width:100%;font-family:lucida sans unicode, lucida grande, sans-serif;\">\r\n"
append response " <tr>\r\n"
append response " <td style=\"width:50%;text-align:left;vertical-align:top;\">\r\n"
append response " <h4>F5 Locations</h4>\r\n"
append response " <ul>\r\n"
append response " <li><a href=\"https://<;IP>/status\">LTM Pool Status at Location 1</a></li>\r\n"
append response " <li><a href=\"https://<;IP>/status\">LTM Pool Status at Location 2</a></li>\r\n"
append response " </ul>\r\n"
append response " </td>\r\n"
append response " <td style=\"width:50%;border-style:dashed;border-width:3px;padding:5px;font-size:90%;text-align:left;vertical-align:top;\">\r\n"
append response " <h4 style=\"font-size:100%;font-weight:bold;color:#FF0000;padding-bottom:10px;\">Critical - No Available Pool Members</h4>\r\n"
foreach { selectedpool } [class get BIG-IP_Pool_Member_Status] {
set thispool [getfield $selectedpool " " 1]
if { [catch {
if { [active_members $thispool] < 1 } {
# Pool Status for pools with no active members
append response " <div style=\"line-height:125%;\">$thispool</div>\r\n"
} else {
# Skip
}
} errmsg ] } {
append response " <div style=\"line-height:125%;\">$thispool <span style=\"font-weight:bold;color:#FF0000\">ERROR: Invalid pool name</span></div>\r\n"
}
}
append response " </td>\r\n"
append response " </tr>\r\n"
append response "</table>\r\n"
append response "</div>\r\n"
# End Table containing "F5 Locations" and "Critical" sections.
# Tables containing Pools with at least one available pool member.
foreach { selectedpool } [class get BIG-IP_Pool_Member_Status] {
set thispool [getfield $selectedpool " " 1]
if { [catch {
if { [active_members $thispool] < 1 } {
# Pool Status for pools with no active members
# Skip. This is implemented above in the first table.
} else {
# Pool Status
append response "<div class=\"layout2\">\r\n"
append response "<table style=\"width:100%;\" id=\"pool_status\">\r\n"
append response " <tr>\r\n"
append response " <th colspan=\"2\">$thispool</th>\r\n"
append response " </tr>\r\n"
append response " <tr>\r\n"
append response " <td style=\"width:50%;text-align:left;vertical-align:top;\">\r\n"
append response " <h4>Pool Member Status</h4>\r\n"
# Pool Member Status Section
append response " <table>\r\n"
foreach { pmem } [members -list $thispool] {
append response " <tr>\r\n"
append response " <td style=\"font-size:90%;\">\r\n"
append response " [join $pmem ":"] is "
set nodestatus "[LB::status pool $thispool member [getfield $pmem " " 1] [getfield $pmem " " 2]]"
if {$nodestatus == "up"} {
append response "<span style=\"font-weight:bold;color:#17ab4a;\">Up</span>\r\n"
} elseif {$nodestatus == "down"} {
append response "<span style=\"font-weight:bold;color:#FF0000;\">Down</span>\r\n"
} elseif {$nodestatus == "session_disabled"} {
append response "<span style=\"font-weight:bold;color:#B7950B;\">Disabled</span>\r\n"
} else {
append response "<span style=\"font-weight:bold;color:#17ab4a;\">$nodestatus</span>\r\n"
}
set nodestatus null
append response " </td>\r\n"
append response " </tr>\r\n"
}
append response " </table>\r\n"
# End Pool Member Status Section
append response " </td>\r\n"
append response " <td style=\"width:50%;font-size:90%;text-align:left;vertical-align:top;\">\r\n"
append response " </td>\r\n"
append response " </tr>\r\n"
append response "</table>\r\n"
append response "</div>\r\n"
append response "<div style=\"padding-bottom:5px;\"></div>\r\n"
}
} errmsg ] } {
append response "<div style=\"line-height:125%;\">$thispool <span style=\"font-weight:bold;color:#FF0000\">ERROR: Invalid pool name</span></div>\r\n"
}
}
# End Tables containing Pools with at least one available pool member.
append response "</body>\r\n"
append response "</html>\r\n"
HTTP::respond 200 content $response "Content-Type" "text/html"
}
log local0.info "$response"
}
Tested this on version:
12.1
- LoyalSoldierAltostratus
Yes, original code in the zip is correct.
- bac81987_341588Nimbostratus
This is great. I am currently using this iRule myself, but most of my pools aren't displaying correctly. The one that is displaying is on the Common partition. All the others that aren't showing correctly have the message "ERROR: Invalid pool name". The only difference I can see is that they are on another partition. I've triple checked the names, and I can confirm they are typed correctly. I've even copied and pasted them in, but no luck.
Is there a way I can monitor all the pools? According to F5, an iRule can reference any object, regardless of the partition in which the referenced object resides.
- LoyalSoldierAltostratus
bac81987,
 
I found this article, and it does appear to be an issue with different partitions being in use. So, you will have to explicitly reference them.
 
From below link:
 
Note that starting in v11, any data-groups that are configured in a partition other than Common must be referenced by /Partition_Name/Data-Group_Name, even by iRules configured in that partition. Data-groups referenced only by name are implicitly presumed to be /Common/Data-Group_Name.
 
My suggestion to try is to try explicitly listing them in the Data Group under:
 
Local Traffic ›› iRules : Data Group List.
 
I'm not utilizing partitions, so am unable to test it myself. If you find this works, or doesn't, please post the results so others will know.
 
Thanks
 
https://devcentral.f5.com/s/feed/0D51T00006i7XiOSAU
 
Another link/source if modifying the iRule code https://clouddocs.f5.com/api/irules/class.html
 
- LucernNimbostratus
I'm thinking this doesn't like underscores in the pool names because it can't find any of mine. Anyone else have this issue? I'm running 12.1.3.6
Looking forward to getting this going!
Thanks!
- bac81987_341588Nimbostratus
Underscores work for me. Currently running 13.1.1
- LoyalSoldierAltostratus
Not sure if this helps... https://support.f5.com/csp/article/K6869
Custom characters for the BIG-IP system Custom characters are not allowed, except for the following: hyphen (-) period (.) underscore (_) The object name must start with a letter or underscore.
- LucernNimbostratus
Right, we're following those rules.. Actually I created a test pool with hyphens and it can't find that either. Something funny is going on.. Hmmmmmm.
Thanks guys!
- bac81987_341588Nimbostratus
I just realized something today. My pools I had were created with an iApp template. When I created a new test pool with hypens and underscores manually, they show up properly on the webpage.
- LoyalSoldierAltostratus
Never used iApps in the creation/testing of this tool, nor were any of my pools created that way.
- LucernNimbostratus
YUP! That's it! The majority of my pools are created via an iApp so I put in one that wasn't and it works! Any chance you could mod it so it would work with iApp pools?
Thanks a bunch for creating this!!