Date

The F5 Load Balancer has a GUI that can be used to configure and manage virtual servers, pools, etc., but I find it cubersome to use as a search tool. It's not that easy if you just want to do a quick look up to find what pool a node belongs to, etc..

What if I have a single html page that shows all the virtual servers, pools and nodes configured? Wouldn't that be cool and convenient?

To accomplish this, I created a python script that makes API calls to the F5 load balancer. Here's the F5 API Reference : https://devcentral.f5.com/wiki/iControl.APIReference.ashx

The script is based on python 2.7 and the bigsuds module. So before you begin, download the bigsuds module :

[skszeto@deuce Downloads]$ sudo pip install bigsuds
Collecting bigsuds
  Downloading https://files.pythonhosted.org/packages/0b/42/4884a0856c9c969910a1585915502ad25163330af75f6247d92cfa3c404e/bigsuds-1.0.6.tar.gz
Collecting suds-jurko>=0.6 (from bigsuds)
  Downloading https://files.pythonhosted.org/packages/bd/6f/54fbf0999a606680d27c69b1ad12dfff62768ecb9fe48524cebda6eb4423/suds-jurko-0.6.tar.bz2 (143kB)
    100% |████████████████████████████████| 153kB 1.4MB/s 
Building wheels for collected packages: bigsuds, suds-jurko
  Running setup.py bdist_wheel for bigsuds ... done
  Stored in directory: /root/.cache/pip/wheels/8b/d2/3e/4ae11e87ed85b0f68ced0193415db6a1af3d9b2c171b8c8923
  Running setup.py bdist_wheel for suds-jurko ... done
  Stored in directory: /root/.cache/pip/wheels/12/68/53/d3902c054e32115da1d45bac442a547a071a86a65db4d77027
Successfully built bigsuds suds-jurko
Installing collected packages: suds-jurko, bigsuds
Successfully installed bigsuds-1.0.6 suds-jurko-0.6
[skszeto@deuce Downloads]$ 

Let's step through the code. It first imports 3 modules :

sys - this module provides some generic fuctions
bigsuds - this module provides access to F5 APIs
socket - use this module to do DNS lookup between hostname and IP address

This script has 11 functions defined. They are simple and easy to understand. Let's take a quick look :

def prepare_html() - this function defines the layout of the html page, color scheme, background, font-size, etc...
def lookup_color(status) - this function decides what color to display based on the status of the device. For example, if the server is down, its status will be displayed as red. Available status colors are : green (good), red (down), blue(up but needs attention) and grey (unknlown).
def end_html(): this function defines the footer for the html page.
def get_virtual_servers(obj) - this function returns the list of configured virtual servers.
def get_virtual_server_status(obj,vs) - this function returns the status of the specified virtual server.
def get_virtual_server_persistence_profile(obj,vs) - this function returns the name of the persistence profile for the specified virtual server.
def get_virtual_server_fallback_persistence_profile(obj,vs) - this function returns the name of the fallback persistence profile for the specified virtual server.
def get_virtual_server_dest_address(obj,vs) - this function returns the destination IP address of the specified virtual server.
def get_virtual_server_default_pool_name(obj,vs) - this function returns the name of the default pool name for the specified virtual server.
def get_status(obj, pool) - this funtion returns the status of the specified virtual server pool.
def get_hostname(address) - this function returns the DNS name of the specified IP address.

This is what the html page would look like :

Pelican

And here is the complete code :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#!/usr/bin/env python
import sys
import bigsuds
import socket

def prepare_html():
    print "<!DOCTYPE html>"
    print "<html>"
    print "<head>"
    print "<style>"
    print "green {"
    print "    color: #008000;"
    print "}"
    print "red {"
    print "    color: #ff0000;"
    print "}"
    print "yellow {"
    print "    color: #FACC2E;"
    print "}"
    print "gray {"
    print "    color: #808080;"
    print "}"
    print "blue {"
    print "    color: #0000FF;"
    print "}"
    print "table, th, td {"
    print "    border: 1px solid black;"
    print "    border-collapse: collapse;"
    print "    text-align: center;"
    print "    font-family: Arial; font-size: 8pt;"
    print "    table-layout:fixed;"
    print "}"
    print "th, td {"
    print "    padding: 2px;"
    print "}"
    print "button.accordion {"
    print "    background-color: #eee;"
    print "    color: #444;"
    print "    cursor: pointer;"
    print "    padding: 10px;"
    print "    width: 100%;"
    print "    border: none;"
    print "    text-align: left;"
    print "    outline: none;"
    print "    font-size: 14px;"
    print "    transition: 0.4s;"
    print "}"

    print "button.accordion.active, button.accordion:hover {"
    print "    background-color: #ccc;"
    print "}"

    print "div.panel {"
    print "    padding: 0 18px;"
    print "    display: yes;"
    print "    background-color: white;"
    print "}"
    print "</style>"
    print "</head>"
    print "<body>"
    print ""

def lookup_color(status):
    colors = [{'AVAILABILITY_STATUS_GREEN': '<green>AVAILABILITY_STATUS_GREEN&#10004;</green>', 'AVAILABILITY_STATUS_RED': '<red>AVAILABILITY_STATUS_RED&#10008;</red>', 'AVAILABILITY_STATUS_BLUE': '<blue>AVAILABILITY_STATUS_BLUE</blue>', 'ENABLED_STATUS_ENABLED': '<green>ENABLED_STATUS_ENABLED&#10004;</green>', 'ENABLED_STATUS_DISABLED': '<yellow>ENABLED_STATUS_DISABLED</yellow>'}]
    unknown_status_color = '<gray>unknown</gray>'

    try:
        color_status = colors[0][status]
        return color_status
    except Exception, e:
        return unknown_status_color

def end_html():
    print '<script>'
    print 'var acc = document.getElementsByClassName("accordion");'
    print 'var i;'
    print ''
    print 'for (i = 0; i < acc.length; i++) {'
    print '    acc[i].onclick = function(){'
        print '        this.classList.toggle("active");'
        print '        var panel = this.nextElementSibling;'
        print '        if (panel.style.display === "block") {'
        print '            panel.style.display = "none";'
        print '        } else {'
        print '            panel.style.display = "block";'
    print '        }'
    print '    }'
    print '}'
    print '</script>'
    print ''
    print '</body>'
    print '</html>'

def get_virtual_servers(obj):
    try:
        return obj.LocalLB.VirtualServer.get_list()
    except Exception, e:
        print e

def get_virtual_server_status(obj,vs):
    try:
        return obj.LocalLB.VirtualServer.get_object_status([vs])
    except Exception, e:
        print e

def get_virtual_server_persistence_profile(obj,vs):
    try:
        return obj.LocalLB.VirtualServer.get_persistence_profile([vs])
    except Exception, e:
        print e

def get_virtual_server_fallback_persistence_profile(obj,vs):
    try:
        return obj.LocalLB.VirtualServer.get_fallback_persistence_profile([vs])
    except Exception, e:
        print e

def get_virtual_server_dest_address(obj,vs):
    try:
        return obj.LocalLB.VirtualServer.get_destination_v2([vs])
    except Exception, e:
        print e

def get_virtual_server_default_pool_name(obj,vs):
    try:
        return obj.LocalLB.VirtualServer.get_default_pool_name([vs])
    except Exception, e:
        print e

def get_status(obj, pool):
    try:
        return obj.LocalLB.Pool.get_member_session_status(pool)
    except Exception, e:
        print e

def get_hostname(address):
    try:
        return socket.gethostbyaddr(address)[0]
    except:
        return address

try:
    b = bigsuds.BIGIP(
    hostname = "my-f5-host",
    username = "my-f5-username",
    password = "my-f5-password",
    )
except Exception, e:
    print e

prepare_html()

virtualservers = get_virtual_servers(b)

for vs in virtualservers:
    vs_name = vs.replace('/Common/','')
    vs_status = get_virtual_server_status(b,vs)
    vs_status_color = lookup_color(vs_status)
    vs_availability_status = vs_status[0]['availability_status']
    vs_availability_status_color = lookup_color(vs_availability_status)
    vs_enabled_status = vs_status[0]['enabled_status']
    vs_enabled_status_color = lookup_color(vs_enabled_status)
    vs_status_description = vs_status[0]['status_description']
    vs_persistence_profile = get_virtual_server_persistence_profile(b,vs)
    if len(vs_persistence_profile[0]) > 0:
        vs_persistence_profile_name = vs_persistence_profile[0][0]['profile_name'].replace('/Common/','')
    else:
        vs_persistence_profile_name = 'None'
    vs_fallback_persistence_profile = get_virtual_server_fallback_persistence_profile(b,vs)
    if vs_fallback_persistence_profile:
        vs_fallback_persistence_profile_name = vs_fallback_persistence_profile[0].replace('/Common/','')
    else:
        vs_fallback_persistence_profile_name = 'None'

    vs_address = get_virtual_server_dest_address(b,vs)
    vs_address_port = vs_address[0]['port']
    vs_address_ip = vs_address[0]['address'].replace('/Common/','')

    if len(vs_address_ip) < 3:
        vs_address_ip = ''

    vs_name = vs.replace('/Common/','')

    print '<!--<button class="accordion"><pre>VIP Name : %s\tIP: %s\tPort: %s"</pre></button>-->' % (vs_name,vs_address_ip,vs_address_port)
    print '<button class="accordion">'
    print '<table style="width: 80%; border; padding: 5px; text-align: left;">'
    print '  <tr>'
    print '    <td>VIP Name : %s</td>' % (vs_name)
    print '    <td>IP: %s</td>' % (vs_address_ip)
    print '    <td>Port: %s</td>' % (vs_address_port)
    print '  </tr>'
    print '</table>'
    print '</button>'
    print '<div class="panel">'
    print '<br>'
    print '<table>'
    print '  <tr>'
    print '    <th>Availability Status</th>'
    print '    <th>Enable Status</th>'
    print '    <th>Status Description</th>'
    print '    <th>Persistence Profile</th>'
    print '    <th>Fallback Persistence Profile</th>'
    print '  </tr>'
    print '  <tr>'
    print '    <td>%s</td>' % (vs_availability_status_color)
    print '    <td>%s</td>' % (vs_enabled_status_color)
    print '    <td>%s</td>' % (vs_status_description)
    print '    <td>%s</td>' % (vs_persistence_profile_name)
    print '    <td>%s</td>' % (vs_fallback_persistence_profile_name)
    print '  </tr>'
    print '</table>'

    pool = get_virtual_server_default_pool_name(b,vs)
    if pool[0]:
        pool_name = pool[0].replace('/Common/','')
        lbmethod = b.LocalLB.Pool.get_lb_method([pool])
        lbmethod_str = str(lbmethod).replace('[','').replace(']','').replace("'","").replace('LB_METHOD_','')
        print '    <h3><pre>Pool Name: %s          LB Method: %s</pre></h3>' % (pool_name, lbmethod_str)
        members = b.LocalLB.Pool.get_member_v2([pool])
        object_status = b.LocalLB.Pool.get_member_object_status([pool], members)
        member_address = b.LocalLB.Pool.get_member_address([pool], members)
        print '    Pool Members:'

        for members, object_status, member_address in zip(members, object_status, member_address):
            count = 0
            print '<table>'
            print '  <tr>'
            print '    <th>Name</th>'
            print '    <th>Server Name / IP</th>'
            print '    <th>Port</th>'
            print '    <th>Availability Status</th>'
            print '    <th>Enable Status</th>'
            print '    <th>Status Description</th>'
            print '    <th>Current Connections</th>'
            print '  </tr>'

            while count < len(members):
                member_port = members[count]['port']
                member_name = members[count]['address'].replace('/Common/','')
                member_statistics = b.LocalLB.Pool.get_member_statistics([pool], [[members[count]]])
                str_member_address = str(member_address[count]).replace('[[','').replace(']]','').replace("'","")
                member_dns_name = get_hostname(str_member_address)
                availability_status = object_status[count]['availability_status']
                availability_status_color = lookup_color(availability_status)
                enabled_status = object_status[count]['enabled_status']
                enabled_status_color = lookup_color(enabled_status)
                status_description = object_status[count]['status_description']
                current_connections = member_statistics[0]['statistics'][0]['statistics'][4]['value']['low']
                print '  <tr>'
                print '    <td>%s</td>' % (member_name)
                print '    <td>%s</td>' % (member_dns_name)
                print '    <td>%s</td>' % (member_port)
                print '    <td>%s</td>' % (availability_status_color)
                print '    <td>%s</td>' % (enabled_status_color)
                print '    <td>%s</td>' % (status_description)
                print '    <td style="text-align:center">%s</td>' % (current_connections)
                print '  </tr>'
                count += 1
            print '</table>'
            print '</div>'
    else:
        print '</div>'

end_html()

Comments

comments powered by Disqus