There are a number of places inside the F5 Dashboard project where the database needs to be modified. A good example of this is from the F5 info gathering page.
The F5 info page is displaying some columns from a database table.
There are a few things going on here so I will start at the top with the refresh button.
Refresh Button
This is what starts the entire process off. This will run a python script that runs a few info gathering GET requests to all the F5s. This is executed sequentially in the order of the F5s.
Once the JSON output is returned from the API’s that is then parsed and we look for certain things as you can see in the table.
This is then saved to the database along with the time it was performed.
The HMTL page will display the database table, and in the top left will grab one of the columns that has the last updated date/time in and display that. I think I am using the last entry in the table for this.
0 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 |
from flask import Blueprint, render_template, redirect, url_for, session, request, jsonify from website.db_controller import DBcontroller from website.info.background_processes import F5BackgroundProcesses from website.models import F5Info from datetime import datetime import json info_blueprint = Blueprint('info',__name__, template_folder='templates/info') @info_blueprint.route('/info', methods = ['GET', 'POST']) def info(): """ Button on the info page to run a script that gets the info for the F5s Table displays; F5 name, Serial Number, Software Version, Mgmt IP, last check status, number of VIPs This all goes into a dictionary """ # Import db table from Models and query it all f5_table = F5Info.query.all() swDB = DBcontroller() lastupdate = swDB.getLastUpdate() print(lastupdate) return render_template('info.html', f5_table=f5_table, lastupdate=lastupdate) @info_blueprint.route('/<hostname>', methods = ['GET', 'POST']) def f5_info(hostname): # var hostname is required # Get details to pass into template f5_stats = DBcontroller() f5_info = f5_stats.get_f5_detail(hostname) # print(f5_info) return render_template('detail.html', hostname=hostname, f5_info=f5_info) @info_blueprint.route('/bg_get_info', methods = ['GET', 'POST']) def bg_get_info(): # List of F5 IP Addresses f5_ip_list = ["172.16.130.36", "172.16.130.13", "172.16.130.14", "172.16.130.15", "1.2.3.4", "172.16.130.12", "172.16.130.21", "172.16.130.28", "172.16.130.22", "172.16.130.30", "172.16.130.20", "172.16.130.23", "172.16.130.29", "5.6.7.8", "172.16.130.36", "172.16.130.13", "172.16.130.14", "172.16.130.15", "172.16.130.12", "172.16.130.21", "172.16.130.28", "9.10.11.12", "172.16.130.22", "172.16.130.30", "172.16.130.20", "172.16.130.23", "172.16.130.29"] get_info = F5BackgroundProcesses() # Get F5 basic Info path = 'cm/device' f5_info = get_info.get_f5_info(f5_ip_list, path) # print(json.dumps(f5_info, sort_keys=True, indent=4)) # Get F5 HA failover active (days) path = 'sys/failover' f5_failover1 = get_info.get_f5_info(f5_ip_list, path) # print(json.dumps(f5_failover1, sort_keys=True, indent=4)) # Get F5 HA failover mate path = 'cm/failover-status' f5_failover2 = get_info.get_f5_info(f5_ip_list, path) # print(json.dumps(f5_failover2, sort_keys=True, indent=4)) now = datetime.now() timestamp = now.strftime("%B, %d, %Y %H:%M:%S") i = 0 my_dict = {} for ip in f5_ip_list: try: # if lastCheck failed, nothing in DB except IP and failure IP if f5_info[i]['lastCheck']: lastCheck = f5_info[i]['lastCheck'] updated = timestamp my_dict[i] = {"hostname":"", "ip":ip, "serial_number":"", "version":"", "failover_active":"", "failover_mate":"", "failover_status":"", "failover_lastmsg":"", "lastCheck":lastCheck, "updated":updated} print(my_dict) except KeyError: hostname = (f5_info[i]['items'][0]['hostname']).split(".")[0] ip = f5_info[i]['items'][0]['managementIp'] serial_number = f5_info[i]['items'][0]['baseMac'] version = f5_info[i]['items'][0]['version'] failover_active = (f5_failover1[i]['apiRawValues']['apiAnonymous']).split(" ")[3] failover_mate = f5_failover2[i]['entries']['https://localhost/mgmt/tm/cm/failover-status/1']['nestedStats']['entries']['remoteDeviceName']['description'] failover_status = f5_failover2[i]['entries']['https://localhost/mgmt/tm/cm/failover-status/1']['nestedStats']['entries']['status']['description'] failover_lastmsg = f5_failover2[i]['entries']['https://localhost/mgmt/tm/cm/failover-status/1']['nestedStats']['entries']['lastMsg']['description'] updated = timestamp lastCheck = "Successful" # Create dict and use that for adding DB. Only 1 DB connection and write needed then my_dict[i] = {"hostname":hostname, "ip":ip, "serial_number":serial_number, "version":version, "failover_active":failover_active, "failover_mate":failover_mate, "failover_status":failover_status, "failover_lastmsg":failover_lastmsg, "lastCheck":lastCheck, "updated":updated} i += 1 # Write to DB in one go f5_stats = DBcontroller() f5_stats.delete_all_f5_info() for key in my_dict: # print(my_dict[key]['hostname']) f5_stats.add_f5_info((my_dict[key]['hostname']), (my_dict[key]['ip']), (my_dict[key]['serial_number']), (my_dict[key]['version']), (my_dict[key]['failover_active']), (my_dict[key]['failover_mate']), (my_dict[key]['failover_status']), (my_dict[key]['failover_lastmsg']), (my_dict[key]['lastCheck']), (my_dict[key]['updated'])) f5_stats.close_db_conn() return jsonify([["Completed", "Collected data, added to DB"]]) |
The Process
The user will go to the /info view. This will query the database table called F5Info and pass that to the HTML template to render. there is some JavaScript to make the table look neater.
The refresh F5 info button may then be pressed to perform the function view called /bg_get_info.
This is what will run through can send the API GET requests to each F5. The return JSON is parsed and then the the database table data is deleted and new data added.
Database Calls
The below code is partial calling another python file that contains all of the database modification commands.
It is doing three things; deleting all data in the F5Info table, then adding new data and finally closing the connection
In all the below I have added the class to make it easier to refer back to. In reality these functions are all part of the same DBcontroller class.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
f5_stats = DBcontroller() f5_stats.delete_all_f5_info() for key in my_dict: # print(my_dict[key]['hostname']) f5_stats.add_f5_info((my_dict[key]['hostname']), (my_dict[key]['ip']), (my_dict[key]['serial_number']), (my_dict[key]['version']), (my_dict[key]['failover_active']), (my_dict[key]['failover_mate']), (my_dict[key]['failover_status']), (my_dict[key]['failover_lastmsg']), (my_dict[key]['lastCheck']), (my_dict[key]['updated'])) f5_stats.close_db_conn() |
Deleting F5Info Table Data
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class DBcontroller: def __init__(self): #self.connection = connection self.basedir = os.path.abspath(os.path.dirname(__file__)) self.connection = sqlite3.connect(self.basedir+'/data.sqlite') def delete_all_f5_info(self): """ F5 Info Table Delete all rows in the f5_domains table :param connection: Connection to the SQLite database :return: """ sql = 'DELETE FROM f5_info_table' cur = self.connection.cursor() cur.execute(sql) self.connection.commit() |
Adding New F5Info Table Data
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class DBcontroller: def __init__(self): #self.connection = connection self.basedir = os.path.abspath(os.path.dirname(__file__)) self.connection = sqlite3.connect(self.basedir+'/data.sqlite') def add_f5_info(self, hostname, ip, serial_number, version, failover_active, failover_mate, failover_status, failover_lastmsg, lastCheck, updated): """ F5 Info Table """ cursor = self.connection.cursor() cursor.execute("INSERT INTO f5_info_table\ (hostname, ip, serial_number, version, failover_active, failover_mate, failover_status, failover_lastmsg, lastCheck, updated)\ VALUES (?,?,?,?,?,?,?,?,?,?)", (hostname, ip, serial_number, version, failover_active, failover_mate, failover_status, failover_lastmsg, lastCheck, updated) ) self.connection.commit() |
Close Database Connection
0 1 2 3 4 5 6 7 8 9 10 |
class DBcontroller: def __init__(self): #self.connection = connection self.basedir = os.path.abspath(os.path.dirname(__file__)) self.connection = sqlite3.connect(self.basedir+'/data.sqlite') def close_db_conn(self): self.connection.close() |
Final Part – Get Last Update Time/Date
0 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 |
class DBcontroller: def __init__(self): #self.connection = connection self.basedir = os.path.abspath(os.path.dirname(__file__)) self.connection = sqlite3.connect(self.basedir+'/data.sqlite') def getLastUpdate(self): """ F5 Info Table Return last runtime """ # select the last ID sql = " SELECT updated from f5_info_table WHERE id = 1;" cur = self.connection.cursor() cur.execute(sql) result = cur.fetchall() try: lastupdate = result[0][0] except: lastupdate = None return lastupdate |