From 4d5d68bba80f6bc52dbc5f7d447e0ce09d4fc660 Mon Sep 17 00:00:00 2001 From: Ajay Dwivedi Date: Thu, 2 May 2024 12:13:04 +0530 Subject: [PATCH] #38 1st draft of scrpt --- .vs/SQLMonitor/v15/.ssms_suo | Bin 67584 -> 70656 bytes .../collect_all_server_alert_messages.py | 273 ++++++++++++++++++ SQLMonitor/tempCodeRunnerFile.py | 2 + .../wrapper-check-instance-availability.bat | 3 + 4 files changed, 278 insertions(+) create mode 100644 SQLMonitor/collect_all_server_alert_messages.py create mode 100644 SQLMonitor/tempCodeRunnerFile.py create mode 100644 SQLMonitor/wrapper-check-instance-availability.bat diff --git a/.vs/SQLMonitor/v15/.ssms_suo b/.vs/SQLMonitor/v15/.ssms_suo index 6f7d1bed0200cf48eb9a31cc974902a58c344404..a23c6aa99662d2166514af40b3e30dbe8b4d1b88 100644 GIT binary patch delta 2086 zcmb`I4NOy46oB7-eXkUG)%u4F2UJ9%%$Cyj(biSc(t;>8)E}mEBnkx_4s}97Ma5?R z%q0f2$H?5&=u^?D0oG^cvcwIPIOmMIEc=a%GjW^Qk1?5=X{Oz|mCmv(OH6iezTR`s zJ@?#m?>+A}xSb0g<+d9qFtMUx7$wRq@+cCCP&Gm9@6I024reZX-s0QyEt!fMX92Xb zGvMsxeDXEiWjB%ltWj)W*Qw!wBDLOv793(m(9Pdv+F;){*p9Ejc>K;cW|E0~pZBqWro@baRu z0kLL5K)9?Xbl15= z)1(X{6|$j}QWedSn2j7r@ezUE?8G=NKMXsZeBYIjB4x2s<*-m;rkpuvGEvcFi_L|= z+-;%Z0|L#L%y|8s;a7y%)y0hYXhy>QXVxmq(6(I*t*H-)3!2B53)Ds(=OBq@2+d+F za-?>K0!p*r4=p{fq8S%+DBp1kBwXz#YGOw&xIIV6ScIfTU5<6`= zWfS%{BV&;kq#62EW?7TdOTx-mY-%!fRwg10&z|gRgfI+y)Koms6m;Yzy6MQ3 z_KkuayX|oMXe;=_92nkl(3V(W@h%Je6n4VIV>_jAGIVr}g^R~LtW|{lZ@QKxf& zv&$jxKAujb3(BOLRrM{kHTBvY(FDG?+`MSg>Fj7R5iajej(V!-IS$SvJn&&JT-!SV z7VQ-vFPurNa3H(|Dti2IyL%EObvHrZ2@YQCE{nDY!x^Zr9lE=rJFm;1JKHE30!@X;uap+;~5&%kRz|o zi>;797*kHe3V&6D?%yJ^7U*=wr?iic2d~)$7!PF2J4Q_r|9J>-eb+c%#5F3wcG4ik zpAQ`(B3Mo~8uWALO*LX&TjMudjn$?aeYIVz)msXTcD+sXTlMx@n^@}svu(^cy2Kaobjfam`ePIYQcBgjGv<$KR^S@E2D3GI(&Do zOuEHEMzd4C`F#oroiBvGi}S#6W0d^o@0<#P*MiXd@fdh?AsKRi+$B3d)hOV~RpY_n zB@+7i6PR)5G;H~$6@qtzT^!*sAcyR@H^A>CeVu(A`9M*}xKFL;3C}|K2TxouR(u~k p_!c|~CIk8_(lmcq_V5SI-?;U%V%EY%J6L?+-Jr2r{u3js{tL>uxgr1n delta 1019 zcmb`FYe*DP6vywGoqcGVO=@Q5TIpt*X`61W2G#gX)I?2$%nWN00zn}uqL3vBDk{_y zZ6A8jSiU|4%`JpJ#I}ayqr?q@AcFcNp|RSQ56tZhEK=0R?&WvS|D1d7nfn-5ujpzQ z+ihC}7HSe>8%S#YaxfUwqB>&pE5Cm3Tp^3s;+pb*4W)+}d0Xe=mS$ zZS!18`2gx^5YbX1p2yt5q#UH|G&)!jsa(=UER$3L^+L9rdM@Q<(U{5d@kPU~1OKHG zE5cm&DeSwY#`QqK9vk&@SvGrKVgBw?dUx&O^bGI%PN2Wnh_WvMEj=l`^x-1`lkVJ7 zt_xWCELMzS1^4it?>P7ON=B6K=<)nSsovp8O)bagsztdQiF^Cf1&0Igs~7phCuN|h zF*r7!!84pbP(}=V=4q)}U?=g~BuD?4)%^e<9_3Mw_CI6C+>xI8LD=WCgJCS`ED0ETh+&A?3^xRe0kr?x!wes9CWHKL9^ZRb%vglM*nYYubTT$B)^^DYfSyGUw#;R_=S3(UaIFRzaAvdB h?Oa2L9r0FR{ZI^6O~v)N^dO*b+KTN{b=@L}zW}zEYJmU% diff --git a/SQLMonitor/collect_all_server_alert_messages.py b/SQLMonitor/collect_all_server_alert_messages.py new file mode 100644 index 0000000..ecd2146 --- /dev/null +++ b/SQLMonitor/collect_all_server_alert_messages.py @@ -0,0 +1,273 @@ +import pyodbc +from prettytable import PrettyTable +#from prettytable import from_db_cursor +import argparse +from datetime import datetime +import os +#from slack_sdk import WebClient +from multiprocessing import Pool +#import math + +parser = argparse.ArgumentParser(description="Script to execute sql query on multiple SQLServer", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument("-s", "--inventory_server", type=str, required=False, action="store", default="localhost", help="Inventory Server") +parser.add_argument("-d", "--inventory_database", type=str, required=False, action="store", default="DBA", help="Inventory Database") +parser.add_argument("--app_name", type=str, required=False, action="store", default="(dba) Collect-AllServerAlertMessages", help="Application Name") +parser.add_argument("--threads", type=int, required=False, action="store", default=4, help="No of parallel threads") + +args=parser.parse_args() + +start_time = datetime.now() + +today = datetime.today() +today_str = today.strftime('%Y-%m-%d') +inventory_server = args.inventory_server +inventory_database = args.inventory_database +app_name = args.app_name +threads = args.threads + +# Get list of servers from Inventory +invCon = pyodbc.connect("Driver={SQL Server Native Client 11.0};" + f"Server={inventory_server};" + f"Database={inventory_database};" + f"App={app_name};" + "Trusted_Connection=yes;") + +invCursor = invCon.cursor() + +sql_get_servers = f""" +declare @max_duration_threshold_minutes int = 120; + +;with cte_instances as ( + select distinct [sql_instance], [sql_instance_port], [database] + from dbo.instance_details id + where is_enabled = 1 and is_alias = 0 and is_available = 1 +) +select id.[sql_instance], [sql_instance_port], [database], + collection_time_utc = coalesce(collection_time_utc, dateadd(minute,-@max_duration_threshold_minutes,sysutcdatetime())) +from cte_instances id +left join ( + select sql_instance, collection_time_utc = max(collection_time_utc) + from [dbo].[alert_history_all_servers] ahas + group by sql_instance + ) ahas + on ahas.sql_instance = id.sql_instance +where 1=1; +""" + +invCursor.execute(sql_get_servers) +servers = invCursor.fetchall() +#invCursor.close() +#invCon.close() + +result_handles = [] +final_result = [] +pt_results = PrettyTable() +successful_servers = [] +failed_servers = [] +pt_successful_servers = PrettyTable() +pt_failed_servers = PrettyTable() +total_servers_count = len(servers) +success_servers_count = 0 +failed_servers_count = 0 + +def query_server(server_row): + #app_name = "(dba) Run-MultiServerQuery" + #app_config = {"app_name": app_name} + server = server_row.sql_instance + database = server_row.database + port = server_row.sql_instance_port + collection_time_utc = server_row.collection_time_utc + + #print(f"Working on [{server}].[{database}]..") + + if port is None: + #connectionString = f'DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={server};DATABASE={database};Trusted_Connection=yes;TrustServerCertificate=YES;App={app_name};UID=grafana;PWD=grafana;' + connectionString = f'DRIVER={{SQL Server Native Client 11.0}};SERVER={server};DATABASE={database};TrustServerCertificate=YES;App={app_name};UID=grafana;PWD=grafana;' + else: + #connectionString = f'DRIVER={{ODBC Driver 18 for SQL Server}};SERVER={server},{port};DATABASE={database};Trusted_Connection=yes;TrustServerCertificate=YES;App={app_name};UID=grafana;PWD=grafana;' + connectionString = f'DRIVER={{SQL Server Native Client 11.0}};SERVER={server},{port};DATABASE={database};TrustServerCertificate=YES;App={app_name};UID=grafana;PWD=grafana;' + + ''' + cnxn = pyodbc.connect("Driver={SQL Server Native Client 11.0};" + f"Server={server},{port};" + f"Database={database};" + f"App={app_name};" + "Trusted_Connection=yes;") + ''' + + sql_query = f""" + SET NOCOUNT ON; + + DECLARE @sql NVARCHAR(max); + DECLARE @params NVARCHAR(max); + DECLARE @sql_instance varchar(125); + DECLARE @collection_time_utc datetime2; + + SET @sql_instance = ?; + SET @collection_time_utc = ?; + + --WAITFOR DELAY '00:00:10'; + + SET @params = N'@sql_instance varchar(125), @collection_time_utc datetime2'; + SET @sql = N' + select ah.collection_time_utc, [sql_instance] = @sql_instance, + ah.server_name, ah.database_name, ah.error_number, + ah.error_severity, ah.error_message, ah.host_instance, + [updated_time_utc] = sysutcdatetime() + from dbo.alert_history ah + where 1=1 + and ah.collection_time_utc > @collection_time_utc + '; + + EXEC sp_executesql @sql + ,@params + ,@sql_instance + ,@collection_time_utc; + """ + + cnxn = pyodbc.connect(connectionString) + #print(sql_query) + cursor = cnxn.cursor() + cursor.execute(sql_query, server, collection_time_utc) + #cursor.execute(sql_query) + result = cursor.fetchall() + cursor.close() + cnxn.close() + + return result + +def pool_handler(): + global threads + pool = Pool(threads) + + print(f"Loop {len(servers)} servers using {threads} threads ..\n") + for server_row in servers: + server = server_row.sql_instance + #print(server) + #pool.apply_async(query_server,(server_row,), callback = log_result) + result = {} + result['server'] = server + result['result_handle'] = pool.apply_async(query_server,(server_row,)) + result_handles.append(result) + + pool.close() + pool.join() + + #print(result_handles) + for server,result in [server_row.values() for server_row in result_handles]: + try: + if result._success: + successful_servers.append(server) + rows = result.get() + for row in rows: + final_result.append(row) + except Exception as e: + print("\n*****************************************************") + print(f"Error occurred for server [{server}]\n") + print(e) + print("*****************************************************\n") + failed_servers.append(server) + + #print(final_result) + + #result_handles = [] + #final_result = [] + #ptable = PrettyTable() + + #for allrows in p.map(query_server, servers): + #for row in allrows: + #final_result.append(row) + + #total_servers_count = len(servers) + global success_servers_count + global failed_servers_count + #success_servers_count = len(final_result) + success_servers_count = len(successful_servers) + failed_servers_count = len(failed_servers) + + #print(final_result) + #pt_results.field_names = [column[0] for column in final_result[0].cursor_description] + #pt_results.add_rows(final_result) + #print(f"Servers with successful connectivity: {success_servers_count}/{total_servers_count}") + #print(pt_results) + + #print(successful_servers) + if success_servers_count > 0: + pt_successful_servers.field_names = ["server",] + for row in successful_servers: + pt_successful_servers.add_row([row,]) + #print(row) + print(f"\nServers with successful connectivity: {success_servers_count}/{total_servers_count}") + print(pt_successful_servers) + else: + print(f"\nNo server with successful connectivity.") + + if failed_servers_count > 0: + #print(failed_servers) + pt_failed_servers.field_names = ["server",] + for row in failed_servers: + pt_failed_servers.add_row([row,]) + #print(row) + print(f"\nServers with failed connectivity: {failed_servers_count}/{total_servers_count}") + print(pt_failed_servers) + else: + print(f"\nNo server with failed connectivity.") + + +def update_inventory(): + if(success_servers_count > 0): + print(f"\nUpdate [is_available] flag for {success_servers_count} servers..") + + #print(final_result) + #print([server_row[0] for server_row in final_result]) + servers_csv = ','.join([f"'{server_row[0]}'" for server_row in final_result]) + #print(servers_csv) + sql_update_online_servers = f""" + update dbo.instance_details set is_available = 1 + where is_enabled = 1 and is_available = 0 + and ( sql_instance in ({servers_csv}) or source_sql_instance in ({servers_csv}) ) + """ + invCursor.execute(sql_update_online_servers) + invCon.commit() + else: + print(f"No successful servers found.") + + if(failed_servers_count > 0): + print(f"\nUpdate [is_available] flag for {failed_servers_count} servers..") + + servers_csv = ','.join([f"'{server}'" for server in failed_servers]) + sql_update_offline_servers = f""" + update dbo.instance_details set is_available = 0, last_unavailability_time_utc = SYSUTCDATETIME() + where is_enabled = 1 and is_available = 1 + and ( sql_instance in ({servers_csv}) or source_sql_instance in ({servers_csv}) ) + """ + invCursor.execute(sql_update_offline_servers) + invCon.commit() + else: + print(f"No failed servers found.") + #invCursor.execute(sql_get_servers) + #servers = invCursor.fetchall() + invCursor.close() + invCon.close() + +if __name__ == '__main__': + + pool_handler() + #update_inventory() + + end_time = datetime.now() + print(f"\n\nTime taken: {end_time-start_time}") + + + +''' +# https://www.analyticsvidhya.com/blog/2024/01/ways-to-convert-python-scripts-to-exe-files/ + +pip install pyinstaller + +PS C:\\Windows\\system32> cd C:\\sqlmonitor\\Work\ +PS C:\\sqlmonitor\\Work> pyinstaller.exe --onefile .\\Raise-AgHealthStateAlert.py + +C:\\sqlmonitor\\Work\\dist\\Raise-AgHealthStateAlert.exe +''' \ No newline at end of file diff --git a/SQLMonitor/tempCodeRunnerFile.py b/SQLMonitor/tempCodeRunnerFile.py new file mode 100644 index 0000000..6a11193 --- /dev/null +++ b/SQLMonitor/tempCodeRunnerFile.py @@ -0,0 +1,2 @@ + +pt_results = PrettyTable() \ No newline at end of file diff --git a/SQLMonitor/wrapper-check-instance-availability.bat b/SQLMonitor/wrapper-check-instance-availability.bat new file mode 100644 index 0000000..63de146 --- /dev/null +++ b/SQLMonitor/wrapper-check-instance-availability.bat @@ -0,0 +1,3 @@ +cd "C:\Program Files\Python312' + +python -u "e:\Github\SQLMonitor\SQLMonitor\check-instance-availability.py" \ No newline at end of file