From 6ca8e7fdb8cc5e64f807caf2abef7833ebee540a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 9 May 2024 16:32:21 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0favicon=E5=9B=BE?= =?UTF-8?q?=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/static/img/favicon.ico | Bin 0 -> 3553 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/common/static/img/favicon.ico b/common/static/img/favicon.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5a618b8d56f68f522b70f6c588b9588188931a95 100644 GIT binary patch literal 3553 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 b037%~u&xOfNpM@h00000NkvXXu0mjfKBBW? literal 0 HcmV?d00001 From e80b335a844d7381f2526ce864a1e13dc4586166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 20 Jun 2024 17:05:35 +0800 Subject: [PATCH 02/14] firset --- common/static/img/favicon.ico | Bin 3553 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/common/static/img/favicon.ico b/common/static/img/favicon.ico index 5a618b8d56f68f522b70f6c588b9588188931a95..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 3553 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 b037%~u&xOfNpM@h00000NkvXXu0mjfKBBW? From e4d02bb4d9a4a4fd4178f2ca3715996f4ed514c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 20 Jun 2024 17:53:19 +0800 Subject: [PATCH 03/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.list b/.env.list index 87f3fc5549..c7bde7b8ba 100644 --- a/.env.list +++ b/.env.list @@ -1,5 +1,5 @@ # https://django-environ.readthedocs.io/en/latest/quickstart.html#usage -# https://docs.djangoproject.com/zh-hans/4.1/ref/settings/ +# https://docs.djangoproject.com/zh-hans/4.1/ref/settings/ DEBUG=false DATABASE_URL=mysql://root:@127.0.0.1:3306/archery CACHE_URL=redis://127.0.0.1:6379/0 From 118504c4c549c628c76cd65cdb5d5fbd5a44fdde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 20 Jun 2024 17:53:56 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E6=92=A4=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.list b/.env.list index c7bde7b8ba..87f3fc5549 100644 --- a/.env.list +++ b/.env.list @@ -1,5 +1,5 @@ # https://django-environ.readthedocs.io/en/latest/quickstart.html#usage -# https://docs.djangoproject.com/zh-hans/4.1/ref/settings/ +# https://docs.djangoproject.com/zh-hans/4.1/ref/settings/ DEBUG=false DATABASE_URL=mysql://root:@127.0.0.1:3306/archery CACHE_URL=redis://127.0.0.1:6379/0 From 4246c626074aef9e18d2c7c993c6fdbf65f0e484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 19 Sep 2024 18:15:03 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20ssl=E5=8F=8A?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E9=AA=8C=E8=AF=81=E8=AF=81=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/engines/__init__.py | 2 +- sql/engines/elasticsearch.py | 12 ++++++------ sql/engines/redis.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sql/engines/__init__.py b/sql/engines/__init__.py index 92b9b2a8b4..b69a43ffeb 100644 --- a/sql/engines/__init__.py +++ b/sql/engines/__init__.py @@ -28,7 +28,7 @@ def __init__(self, instance: Instance = None): self.password = instance.password self.db_name = instance.db_name self.mode = instance.mode - self.is_ssl = instance.is_ssl + #self.is_ssl = instance.is_ssl # 判断如果配置了隧道则连接隧道,只测试了MySQL if self.instance.tunnel: diff --git a/sql/engines/elasticsearch.py b/sql/engines/elasticsearch.py index 1c135aad76..a4ecd98e47 100644 --- a/sql/engines/elasticsearch.py +++ b/sql/engines/elasticsearch.py @@ -1046,13 +1046,13 @@ def get_connection(self, db_name=None): if self.conn: return self.conn if self.instance: - scheme = "https" if self.is_ssl else "http" + scheme = "https" if self.instance.is_ssl else "http" hosts = [ { "host": self.host, "port": self.port, "scheme": scheme, - "use_ssl": self.is_ssl, + "use_ssl": self.instance.is_ssl, } ] http_auth = ( @@ -1064,7 +1064,7 @@ def get_connection(self, db_name=None): self.conn = Elasticsearch( hosts=hosts, http_auth=http_auth, - verify_certs=True, # 需要证书验证 + verify_certs=self.instance.verify_ssl, # 需要证书验证 ) except Exception as e: raise Exception(f"Elasticsearch 连接建立失败: {str(e)}") @@ -1095,13 +1095,13 @@ def get_connection(self, db_name=None): if self.conn: return self.conn if self.instance: - scheme = "https" if self.is_ssl else "http" + scheme = "https" if self.instance.is_ssl else "http" hosts = [ { "host": self.host, "port": self.port, "scheme": scheme, - "use_ssl": self.is_ssl, + "use_ssl": self.instance.is_ssl, } ] http_auth = ( @@ -1114,7 +1114,7 @@ def get_connection(self, db_name=None): self.conn = OpenSearch( hosts=hosts, http_auth=http_auth, - verify_certs=True, # 开启证书验证 + verify_certs=self.instance.verify_ssl, # 开启证书验证 ) except Exception as e: raise Exception(f"OpenSearch 连接建立失败: {str(e)}") diff --git a/sql/engines/redis.py b/sql/engines/redis.py index 4df0b258f8..c22cf73b75 100644 --- a/sql/engines/redis.py +++ b/sql/engines/redis.py @@ -35,7 +35,7 @@ def get_connection(self, db_name=None): encoding_errors="ignore", decode_responses=True, socket_connect_timeout=10, - ssl=self.is_ssl, + ssl=self.instance.is_ssl, ) else: return redis.Redis( @@ -47,7 +47,7 @@ def get_connection(self, db_name=None): encoding_errors="ignore", decode_responses=True, socket_connect_timeout=10, - ssl=self.is_ssl, + ssl=self.instance.is_ssl, ) name = "Redis" From 913d380b9ad8dd0f3b14014af0d402d824e637db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 19 Sep 2024 18:18:38 +0800 Subject: [PATCH 06/14] =?UTF-8?q?is=5Fssl=E4=BD=BF=E7=94=A8=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E7=9A=84=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/engines/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/engines/__init__.py b/sql/engines/__init__.py index b69a43ffeb..09ee6f1e2b 100644 --- a/sql/engines/__init__.py +++ b/sql/engines/__init__.py @@ -28,7 +28,6 @@ def __init__(self, instance: Instance = None): self.password = instance.password self.db_name = instance.db_name self.mode = instance.mode - #self.is_ssl = instance.is_ssl # 判断如果配置了隧道则连接隧道,只测试了MySQL if self.instance.tunnel: From bc5e992630e7bf6529fc1dc41030a6709f488784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 19 Sep 2024 18:39:27 +0800 Subject: [PATCH 07/14] =?UTF-8?q?redis=E6=B7=BB=E5=8A=A0=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/db_diagnostic.py | 3 +- sql/engines/redis.py | 15 +++++ sql/templates/dbdiagnostic.html | 111 +++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 3 deletions(-) diff --git a/sql/db_diagnostic.py b/sql/db_diagnostic.py index ca01b0bc96..683d266d27 100644 --- a/sql/db_diagnostic.py +++ b/sql/db_diagnostic.py @@ -31,9 +31,8 @@ def process(request): query_engine = get_engine(instance=instance) query_result = None - if instance.db_type == "mysql": + if instance.db_type in ["mysql", "redis"]: query_result = query_engine.processlist(command_type) - elif instance.db_type == "mongo": query_result = query_engine.current_op(command_type) elif instance.db_type == "oracle": diff --git a/sql/engines/redis.py b/sql/engines/redis.py index c22cf73b75..5e46c797b9 100644 --- a/sql/engines/redis.py +++ b/sql/engines/redis.py @@ -131,6 +131,21 @@ def query_check(self, db_name=None, sql="", limit_num=0): result["msg"] = "禁止执行该命令!" return result + def processlist(self, command_type): + """获取连接信息""" + sql = "client list" + result_set = ResultSet(full_sql=sql) + conn = self.get_connection(db_name=0) + clients = conn.client_list() + # 根据空闲时间排序 + sort_by = "idle" + reverse = False + clients = sorted( + clients, key=lambda client: client.get(sort_by), reverse=reverse + ) + result_set.rows = clients + return result_set + def query(self, db_name=None, sql="", limit_num=0, close_conn=True, **kwargs): """返回 ResultSet""" result_set = ResultSet(full_sql=sql) diff --git a/sql/templates/dbdiagnostic.html b/sql/templates/dbdiagnostic.html index eab4ee6933..3952cbf257 100644 --- a/sql/templates/dbdiagnostic.html +++ b/sql/templates/dbdiagnostic.html @@ -27,6 +27,7 @@ +
@@ -326,6 +327,111 @@ return html.join(''); } ] + ,[ + 'redis', + ["All","",""], + [{ + title: '', // 用于多选框 + field: 'checkbox', + checkbox: true + }, { + title: 'Id', + field: 'id', + sortable: true + }, { + title: '远程地址', + field: 'addr', + sortable: true + }, { + title: '本地地址', + field: 'laddr', + sortable: true + }, { + title: '客户端名称', + field: 'name', + sortable: true + }, { + title: '用户', + field: 'user', + sortable: true + }, + { + title: '数据库', + field: 'db', + sortable: true + }, { + title: '连接耗时(秒)', + field: 'age', + sortable: true + }, { + title: '空闲时间(秒)', + field: 'idle', + sortable: true + }, { + title: '命令', + field: 'cmd', + sortable: true + }, { + title: '总内存', + field: 'tot-mem', + sortable: true + },{ + title: '输出内存', + field: 'omem', + sortable: true + }, { + title: '标志', + field: 'flags', + sortable: true + },{ + title: '文件描述符', + field: 'fd', + sortable: true + },{ + title: '订阅数', + field: 'sub', + sortable: true + }, { + title: '模式订阅数', + field: 'psub', + sortable: true + }, { + title: 'MULTI 队列长度', + field: 'multi', + sortable: true + }, { + title: '查询缓冲区', + field: 'qbuf', + sortable: true + }, { + title: '查询缓冲区空闲', + field: 'qbuf-free', + sortable: true + }, { + title: '参数内存', + field: 'argv-mem', + sortable: true + }, { + title: '输出缓冲区长度', + field: 'obl', + sortable: true + }, { + title: '输出链长度', + field: 'oll', + sortable: true + }, { + title: '事件文件', + field: 'events', + sortable: true + }, { + title: '重定向', + field: 'redir', + sortable: true + }], + function (index, row) { + var html = []; + } + ] ] @@ -936,7 +1042,7 @@ url: "/group/user_all_instances/", dataType: "json", data: { - db_type: ['mysql','mongo', 'oracle'] + db_type: ['mysql','mongo', 'oracle','redis'] }, complete: function () { //如果已选择instance_name,进入页面自动填充,并且重置激活id @@ -955,6 +1061,7 @@ $("#optgroup-mysql").empty(); $("#optgroup-mongo").empty(); $("#optgroup-oracle").empty(); + $("#optgroup-redis").empty(); for (let i = 0; i < result.length; i++) { let instance = ""; // $("#instance_name").append(instance); @@ -964,6 +1071,8 @@ $("#optgroup-mongo").append(instance); } else if (result[i]['db_type'] === 'oracle') { $("#optgroup-oracle").append(instance); + } else if (result[i]['db_type'] === 'redis') { + $("#optgroup-redis").append(instance); } } $('#instance_name').selectpicker('render'); From e6a97538dc03ad287b958c08dbd593377b14f90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 19 Sep 2024 19:04:14 +0800 Subject: [PATCH 08/14] all --- sql/templates/dbdiagnostic.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/templates/dbdiagnostic.html b/sql/templates/dbdiagnostic.html index 3952cbf257..2bb208f7ea 100644 --- a/sql/templates/dbdiagnostic.html +++ b/sql/templates/dbdiagnostic.html @@ -329,7 +329,7 @@ ] ,[ 'redis', - ["All","",""], + ["All"], [{ title: '', // 用于多选框 field: 'checkbox', From 5031be84ba2fa2689671c34fe44fa8ac5a26838e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Thu, 19 Sep 2024 19:05:57 +0800 Subject: [PATCH 09/14] cicd From e8f12974acecc46b87883c5dcf51d0559b9564f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Fri, 20 Sep 2024 10:39:20 +0800 Subject: [PATCH 10/14] =?UTF-8?q?processlist=E6=96=B9=E6=B3=95=E5=B7=B2?= =?UTF-8?q?=E6=8F=90=E5=8D=87=E4=B8=BA=E7=88=B6=E7=B1=BB=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/db_diagnostic.py | 21 +++++++-------------- sql/engines/__init__.py | 4 ++++ sql/engines/cloud/aliyun_rds.py | 2 +- sql/engines/mongo.py | 2 +- sql/engines/mysql.py | 2 +- sql/engines/oracle.py | 2 +- sql/engines/redis.py | 2 +- sql/engines/tests.py | 8 ++++---- sql/templates/dbdiagnostic.html | 24 ++++++++---------------- 9 files changed, 28 insertions(+), 39 deletions(-) diff --git a/sql/db_diagnostic.py b/sql/db_diagnostic.py index 683d266d27..6f755c086f 100644 --- a/sql/db_diagnostic.py +++ b/sql/db_diagnostic.py @@ -22,6 +22,9 @@ def process(request): instance_name = request.POST.get("instance_name") command_type = request.POST.get("command_type") + request_post_kwargs = { + key: value for key, value in request.POST.items() if key != "command_type" + } try: instance = user_instances(request.user).get(instance_name=instance_name) @@ -31,20 +34,10 @@ def process(request): query_engine = get_engine(instance=instance) query_result = None - if instance.db_type in ["mysql", "redis"]: - query_result = query_engine.processlist(command_type) - elif instance.db_type == "mongo": - query_result = query_engine.current_op(command_type) - elif instance.db_type == "oracle": - query_result = query_engine.session_list(command_type) - else: - result = { - "status": 1, - "msg": "暂时不支持{}类型数据库的进程列表查询".format(instance.db_type), - "data": [], - } - return HttpResponse(json.dumps(result), content_type="application/json") - + # processlist方法已提升为父类方法,简化此处的逻辑。进程添加新数据库支持时,改前端即可。 + query_result = query_engine.processlist( + command_type=command_type, **request_post_kwargs + ) if query_result: if not query_result.error: processlist = query_result.to_dict() diff --git a/sql/engines/__init__.py b/sql/engines/__init__.py index 09ee6f1e2b..939a100b13 100644 --- a/sql/engines/__init__.py +++ b/sql/engines/__init__.py @@ -103,6 +103,10 @@ def server_version(self): """返回引擎服务器版本,返回对象为tuple (x,y,z)""" return tuple() + def processlist(self, command_type, **kwargs) -> ResultSet: + """获取连接信息""" + return ResultSet() + def kill_connection(self, thread_id): """终止数据库连接""" diff --git a/sql/engines/cloud/aliyun_rds.py b/sql/engines/cloud/aliyun_rds.py index efb13eaf41..4f4b81f1cc 100644 --- a/sql/engines/cloud/aliyun_rds.py +++ b/sql/engines/cloud/aliyun_rds.py @@ -15,7 +15,7 @@ def __init__(self, instance=None): self.instance_name = instance.instance_name # 将sql/aliyun_rds.py的函数迁移值此 - def processlist(self, command_type): + def processlist(self, command_type, **kwargs): if command_type is None or command_type == "": command_type = "Query" diff --git a/sql/engines/mongo.py b/sql/engines/mongo.py index a989067941..fe491c6057 100644 --- a/sql/engines/mongo.py +++ b/sql/engines/mongo.py @@ -1210,7 +1210,7 @@ def fill_query_columns(cursor, columns): cols.append(key) return cols - def current_op(self, command_type): + def processlist(self, command_type, **kwargs): """ 获取当前连接信息 diff --git a/sql/engines/mysql.py b/sql/engines/mysql.py index 369931791b..d47b2b8a92 100644 --- a/sql/engines/mysql.py +++ b/sql/engines/mysql.py @@ -762,7 +762,7 @@ def osc_control(self, **kwargs): """ return self.inc_engine.osc_control(**kwargs) - def processlist(self, command_type): + def processlist(self, command_type, **kwargs): """获取连接信息""" base_sql = "select id, user, host, db, command, time, state, ifnull(info,'') as info from information_schema.processlist" # escape diff --git a/sql/engines/oracle.py b/sql/engines/oracle.py index 747f84f8d1..4345431e1e 100644 --- a/sql/engines/oracle.py +++ b/sql/engines/oracle.py @@ -1451,7 +1451,7 @@ def execute(self, db_name=None, sql="", close_conn=True, parameters=None): self.close() return result - def session_list(self, command_type): + def processlist(self, command_type, **kwargs): """获取会话信息""" base_sql = """select s.sid, diff --git a/sql/engines/redis.py b/sql/engines/redis.py index 5e46c797b9..1f839988b2 100644 --- a/sql/engines/redis.py +++ b/sql/engines/redis.py @@ -131,7 +131,7 @@ def query_check(self, db_name=None, sql="", limit_num=0): result["msg"] = "禁止执行该命令!" return result - def processlist(self, command_type): + def processlist(self, command_type, **kwargs): """获取连接信息""" sql = "client list" result_set = ResultSet(full_sql=sql) diff --git a/sql/engines/tests.py b/sql/engines/tests.py index eea86f31c3..63147e6c0c 100644 --- a/sql/engines/tests.py +++ b/sql/engines/tests.py @@ -1497,11 +1497,11 @@ def test_execute(self, _connect, _cursor, _execute): self.assertIsInstance(execute_result, ResultSet) @patch("sql.engines.oracle.OracleEngine.query") - def test_session_list(self, _query): + def test_processlist(self, _query): new_engine = OracleEngine(instance=self.ins) _query.return_value = ResultSet() for command_type in ["All", "Active", "Others"]: - r = new_engine.session_list(command_type) + r = new_engine.processlist(command_type) self.assertIsInstance(r, ResultSet) @patch("sql.engines.oracle.OracleEngine.query") @@ -1803,7 +1803,7 @@ def test_fill_query_columns(self): self.assertEqual(cols, ["_id", "title", "tags", "likes", "text", "author"]) @patch("sql.engines.mongo.MongoEngine.get_connection") - def test_current_op(self, mock_get_connection): + def test_processlist(self, mock_get_connection): class Aggregate: def __enter__(self): yield {"client": "single_client"} @@ -1817,7 +1817,7 @@ def __exit__(self, *arg, **kwargs): mock_get_connection.return_value = mock_conn command_types = ["Full", "All", "Inner", "Active"] for command_type in command_types: - result_set = self.engine.current_op(command_type) + result_set = self.engine.processlist(command_type) self.assertIsInstance(result_set, ResultSet) @patch("sql.engines.mongo.MongoEngine.get_connection") diff --git a/sql/templates/dbdiagnostic.html b/sql/templates/dbdiagnostic.html index 2bb208f7ea..3d5e234ec5 100644 --- a/sql/templates/dbdiagnostic.html +++ b/sql/templates/dbdiagnostic.html @@ -1037,12 +1037,14 @@ $(document).ready(function () { //获取用户实例列表 $(function () { + // 会话管理-支持的数据库类型 + supportedDbType=['mysql','mongo', 'oracle','redis','opensearch'] $.ajax({ type: "get", url: "/group/user_all_instances/", dataType: "json", data: { - db_type: ['mysql','mongo', 'oracle','redis'] + db_type: supportedDbType }, complete: function () { //如果已选择instance_name,进入页面自动填充,并且重置激活id @@ -1057,23 +1059,13 @@ if (data.status === 0) { let result = data['data']; allInstances = result; - // $("#instance_name").empty(); - $("#optgroup-mysql").empty(); - $("#optgroup-mongo").empty(); - $("#optgroup-oracle").empty(); - $("#optgroup-redis").empty(); + supportedDbType.forEach(function(db) { + $("#optgroup-" + db).empty(); + }); for (let i = 0; i < result.length; i++) { let instance = ""; - // $("#instance_name").append(instance); - if (result[i]['db_type'] === 'mysql') { - $("#optgroup-mysql").append(instance); - } else if (result[i]['db_type'] === 'mongo') { - $("#optgroup-mongo").append(instance); - } else if (result[i]['db_type'] === 'oracle') { - $("#optgroup-oracle").append(instance); - } else if (result[i]['db_type'] === 'redis') { - $("#optgroup-redis").append(instance); - } + var dbType = result[i]['db_type']; + $("#optgroup-" + dbType).append(instance); } $('#instance_name').selectpicker('render'); $('#instance_name').selectpicker('refresh'); From a0dbfd736867e857359523684a80dbd65f8701ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Fri, 20 Sep 2024 10:42:19 +0800 Subject: [PATCH 11/14] =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=AE=A1=E7=90=86-?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=9A=84=E6=95=B0=E6=8D=AE=E5=BA=93=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/templates/dbdiagnostic.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/templates/dbdiagnostic.html b/sql/templates/dbdiagnostic.html index 3d5e234ec5..76eb34aaf1 100644 --- a/sql/templates/dbdiagnostic.html +++ b/sql/templates/dbdiagnostic.html @@ -1038,7 +1038,7 @@ //获取用户实例列表 $(function () { // 会话管理-支持的数据库类型 - supportedDbType=['mysql','mongo', 'oracle','redis','opensearch'] + supportedDbType=['mysql','mongo', 'oracle','redis'] $.ajax({ type: "get", url: "/group/user_all_instances/", From 38a39dd36654c4e68bcca34750a889a567e57319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Fri, 20 Sep 2024 10:53:42 +0800 Subject: [PATCH 12/14] =?UTF-8?q?=E6=B5=8B=E8=AF=95=20processlist=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=EF=BC=8C=E6=A8=A1=E6=8B=9F=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=B9=B6=E8=BF=94=E5=9B=9E=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/engines/tests.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sql/engines/tests.py b/sql/engines/tests.py index 63147e6c0c..4638708213 100644 --- a/sql/engines/tests.py +++ b/sql/engines/tests.py @@ -487,6 +487,43 @@ def test_execute_workflow_success(self, _execute_command): self.assertIsInstance(execute_result, ReviewSet) self.assertEqual(execute_result.rows[0].__dict__.keys(), row.__dict__.keys()) + @patch("sql.engines.redis.RedisEngine.get_connection") + def test_processlist(self, mock_get_connection): + """测试 processlist 方法,模拟获取连接并返回客户端列表""" + + # 模拟 Redis 连接的客户端列表 + mock_conn = Mock() + + return_value_mock = [ + {"id": "1", "idle": 10, "name": "client_1"}, + {"id": "2", "idle": 5, "name": "client_2"}, + {"id": "3", "idle": 20, "name": "client_3"}, + ] + mock_conn.client_list.return_value = return_value_mock + + # 设置 get_connection 返回模拟连接 + mock_get_connection.return_value = mock_conn + + # 创建 RedisEngine 实例 + new_engine = RedisEngine(instance=self.ins) + + # 调用 processlist 方法并测试其返回值 + command_types = ["All"] # 假设支持的命令类型 + for command_type in command_types: + result_set = new_engine.processlist(command_type=command_type) + + # 验证返回值是 ResultSet 实例 + self.assertIsInstance(result_set, ResultSet) + + # 验证返回的客户端列表被正确排序 + sorted_clients = sorted( + return_value_mock, key=lambda client: client.get("idle"), reverse=False + ) + self.assertEqual(result_set.rows, sorted_clients) + + # 验证 get_connection 是否被调用 + mock_get_connection.assert_called() + class TestPgSQL(TestCase): @classmethod From 7808b84ed601905d4a48e898ea5f99566729bc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Fri, 20 Sep 2024 13:43:52 +0800 Subject: [PATCH 13/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=90=8Drequest=5Fkwargs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/db_diagnostic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/db_diagnostic.py b/sql/db_diagnostic.py index 6f755c086f..c12ab2c296 100644 --- a/sql/db_diagnostic.py +++ b/sql/db_diagnostic.py @@ -22,7 +22,7 @@ def process(request): instance_name = request.POST.get("instance_name") command_type = request.POST.get("command_type") - request_post_kwargs = { + request_kwargs = { key: value for key, value in request.POST.items() if key != "command_type" } @@ -36,7 +36,7 @@ def process(request): query_result = None # processlist方法已提升为父类方法,简化此处的逻辑。进程添加新数据库支持时,改前端即可。 query_result = query_engine.processlist( - command_type=command_type, **request_post_kwargs + command_type=command_type, **request_kwargs ) if query_result: if not query_result.error: From ab3981fad08f2e208436317f8b7fd2edb87db1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=A3=9E?= Date: Fri, 20 Sep 2024 13:46:53 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=90=8Drequest=5Fkwargs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/db_diagnostic.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sql/db_diagnostic.py b/sql/db_diagnostic.py index c12ab2c296..b163c09b95 100644 --- a/sql/db_diagnostic.py +++ b/sql/db_diagnostic.py @@ -35,9 +35,7 @@ def process(request): query_engine = get_engine(instance=instance) query_result = None # processlist方法已提升为父类方法,简化此处的逻辑。进程添加新数据库支持时,改前端即可。 - query_result = query_engine.processlist( - command_type=command_type, **request_kwargs - ) + query_result = query_engine.processlist(command_type=command_type, **request_kwargs) if query_result: if not query_result.error: processlist = query_result.to_dict()