CodeShare
Have some code. Share some code.
cancel
Showing results for 
Search instead for 
Did you mean: 
LoyalSoldier
Altostratus
Altostratus

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 0151T000003d9DKQAY.png

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

Comments
LoyalSoldier
Altostratus
Altostratus

Found this article. See if using their iApp examples will work with putting it in the Data Group List.

 

https://devcentral.f5.com/s/feed/0D51T00006i7hIpSAI

 

bac81987_341588
Nimbostratus
Nimbostratus

Found a fix for this. If your pool was created via an iApp, place the Partition / Path in the data group list string before the pool name.

 

example: /Common/ent_exch.app/ent_exch_ad_pool7

 

@bac81987,

 

I haven't tried Iapp yet, but like you mentioned giving the complete path fixes it. But may i know what is "ent_exch.app" in your path. Is that how pool names created with some folder when its done through Iapp, Because this doesn't look like a partition name.

 

bac81987_341588
Nimbostratus
Nimbostratus

"ent_exch.app" is my path name. It's whatever you named your iApp template when creating it.

 

Gotcha, its the Iapp behaviour then. Thanks.

 

Lucern
Nimbostratus
Nimbostratus

Ohh yeah! That works! Nice find! I see that if you go into a pool and look at Statistics you'll see the full path name.

 

Well that was an easy fix! 🙂

 

Thanks!

 

kend
Nimbostratus
Nimbostratus

Is there any way to schedule saving the output to a html file and have it automatically emailed?

 

@Ken,

Thats a simple html response... You can simply curl the url and get the output. Save the output in the format you need.

Lets say you have built this setup already.

Access:

https:///status

will show your page.

Do a curl & append the output to a file,

curl -k https:///status > /var/tmp/status-output.html

Build a bash script with sendmail & send the output as attachment. Hope it helps.

kend
Nimbostratus
Nimbostratus

Thanks for the reply. I am not that familiar with bash script and sendmail. Could you please provide an example script I can use?

 

stboiss
Nimbostratus
Nimbostratus

Can someone post the code again ?

Steven_Levchenk
Nimbostratus
Nimbostratus

Where is the code for the iRule? I just see "74839" in the code section.

 

Thanks,

Steve

gpoverland
Nimbostratus
Nimbostratus

Does anyone know where I can find the source code for this solution? Thanks

LiefZimmerman
Community Manager
Community Manager

 - did you happen to edit this code snippet down in this way? or was this a FallenSoldier (pardon the pun) in our site transition? If you still have it can you re-post it here? If not...I'll see if I can find it in our wayback machine.

 

adding  - so he can be notified of updates if you have them.

 , Ive been using it for some years, have the code somewhere in my F5's. I'll wait for a day for the Op to repost, if not I'll send it to you, so you can update this thread.

bcarreker
Cirrus
Cirrus

If someone could re-upload the iRule for this, it would be GREATLY appreciated.

LoyalSoldier
Altostratus
Altostratus

 - The code must have been dropped during the site transition.

 

I have reapplied the code to the post above.

bcarreker
Cirrus
Cirrus

Thanks a lot!

LiefZimmerman
Community Manager
Community Manager

  &  - it's been a hot minute but LoyalSoldier fixed up the iRule code today.

My apologies that I didn't catch this a bit sooner.

kend
Nimbostratus
Nimbostratus

Is there anyway to have the node name appear as well? For example, NODENAME:IP:Port.

LoyalSoldier
Altostratus
Altostratus

 

 

Below is from a previous comment when I built the script:

"As far as adding the hostname... I looked into that while building the script and there was no easy/known way to incorporate the hostname from an iRule command, such as "[members -list $thispool]". The "members" command, for example, only pulls the IP and Port. Never tried looking at adding the description field.

With that said, you may be able to get those fields added using iCall, but I don't have enough experience with iCall, or time, to attempt it. If you or someone else wants to feel free.

One such example: https://devcentral.f5.com/s/feed/0D51T00006pY5mySAC"

 

To my knowledge nothing has changed since this script was built, but I haven't re-looked into it either.

 

 

TroublesBricking
Nimbostratus
Nimbostratus

I have my app team asking for something that I think this will work for. However, I'm not sure if this will still works correctly on version 16. 

I have created the datagroup and populated it with a several pool names. 
Created iRule by copy/paste code from this thread.
Created SSL VIP with cert.
Added iRule.
I can get to the /status page and the data looks like its there, but it is just one long line of text instead of the nifty graphical page given as an example. I've never seen an iRule that had boxes like this one shows.

Any help would be appreciated.

LoyalSoldier
Altostratus
Altostratus

It was brought to my attention the original code has been quite a bit mangled somehow from the hosting application. Here is a repost of the original 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"
}

 

 

Version history
Last update:
‎19-Sep-2022 22:31
Updated by:
Contributors