diff --git a/.gitignore b/.gitignore
index e2ef12599..f19ace758 100644
--- a/.gitignore
+++ b/.gitignore
@@ -180,4 +180,3 @@ plugins/frp
plugins/file_search
plugins/proxysql
plugins/tidb
-plugins/task_manager
diff --git a/plugins/task_manager/ico.png b/plugins/task_manager/ico.png
new file mode 100644
index 000000000..60fa27d66
Binary files /dev/null and b/plugins/task_manager/ico.png differ
diff --git a/plugins/task_manager/index.html b/plugins/task_manager/index.html
new file mode 100755
index 000000000..b51b420c2
--- /dev/null
+++ b/plugins/task_manager/index.html
@@ -0,0 +1,554 @@
+
+
+
+
+
+
+
+
+
+
+ CPU
+ 内存
+ 磁盘
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/task_manager/index.py b/plugins/task_manager/index.py
new file mode 100755
index 000000000..f2f22f90e
--- /dev/null
+++ b/plugins/task_manager/index.py
@@ -0,0 +1,62 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import re
+
+sys.path.append(os.getcwd() + "/class/core")
+import mw
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+def getPluginName():
+ return 'task_manager'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+def getArgs():
+ args = sys.argv[3:]
+ tmp = {}
+ args_len = len(args)
+
+ if args_len == 1:
+ t = args[0].strip('{').strip('}')
+ if t.strip() == '':
+ tmp = []
+ else:
+ t = t.split(':')
+ tmp[t[0]] = t[1]
+ tmp[t[0]] = t[1]
+ elif args_len > 1:
+ for i in range(len(args)):
+ t = args[i].split(':')
+ tmp[t[0]] = t[1]
+ return tmp
+
+def checkArgs(data, ck=[]):
+ for i in range(len(ck)):
+ if not ck[i] in data:
+ return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
+ return (True, mw.returnJson(True, 'ok'))
+
+def status():
+ return 'start'
+
+
+if __name__ == "__main__":
+ func = sys.argv[1]
+ if func == 'status':
+ print(status())
+ else:
+ print('error')
diff --git a/plugins/task_manager/info.json b/plugins/task_manager/info.json
new file mode 100755
index 000000000..bdfcdda38
--- /dev/null
+++ b/plugins/task_manager/info.json
@@ -0,0 +1,17 @@
+{
+ "sort": 7,
+ "ps": "轻松管理进程、流量监控、启动项、用户、服务、计划任务、会话[开发中]",
+ "name": "task_manager",
+ "title": "任务管理器",
+ "shell": "install.sh",
+ "versions":"1.0",
+ "tip": "soft",
+ "checks": "server/task_manager",
+ "path": "server/task_manager",
+ "display": 1,
+ "author": "task_manager",
+ "date": "2024-06-01",
+ "home": "task_manager",
+ "type": 0,
+ "pid": "4"
+}
\ No newline at end of file
diff --git a/plugins/task_manager/install.sh b/plugins/task_manager/install.sh
new file mode 100755
index 000000000..6cb2d3597
--- /dev/null
+++ b/plugins/task_manager/install.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
+export PATH
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+
+install_tmp=${rootPath}/tmp/mw_install.pl
+VERSION=$2
+
+Install_App()
+{
+ echo '正在安装脚本文件...' > $install_tmp
+ mkdir -p $serverPath/task_manager
+
+ echo "$VERSION" > $serverPath/task_manager/version.pl
+ echo "安装任务管理器成功"
+}
+
+Uninstall_App()
+{
+ rm -rf $serverPath/task_manager
+ echo "卸载任务管理器成功"
+}
+
+action=$1
+if [ "${1}" == 'install' ];then
+ Install_App
+else
+ Uninstall_App
+fi
diff --git a/plugins/task_manager/js/task_manager.js b/plugins/task_manager/js/task_manager.js
new file mode 100644
index 000000000..413d045bd
--- /dev/null
+++ b/plugins/task_manager/js/task_manager.js
@@ -0,0 +1,1103 @@
+
+function tmPostCallback(method, args, callback, version='1.0'){
+ var req_data = {};
+ req_data['name'] = 'task_manager';
+ req_data['func'] = method;
+ req_data['script']='task_manager_index';
+ args['version'] = version;
+
+ if (typeof(args) == 'string' && args == ''){
+ req_data['args'] = JSON.stringify(toArrayObject(args));
+ } else {
+ req_data['args'] = JSON.stringify(args);
+ }
+
+ $.post('/plugins/callback', req_data, function(data) {
+ if(typeof(callback) == 'function'){
+ callback(data);
+ }
+ },'json');
+}
+
+var tab_name = 'p_list';
+var search_val = '';
+var select_pid = undefined; // 当前选中进程的id
+var realProcess = []; // 进程数组
+var originProcess = []; // 当前进程展示的列表
+var wrapPid = {}; // 展开的父进程
+var TaskProcessLayerIndex = ''; // 进程详情弹窗的index
+var canScroll2TaskMangerPossess = true; // 是否可以定位到选中的进程
+
+$('.t-mana .man-menu-sub span').click(function () {
+ $(this).siblings().removeClass("on");
+ tab_name = $(this).attr('class');
+ $(this).addClass("on")
+ // console.log(tab_name);
+ if (tab_name == 'p_resource') {
+ $('.resource-panel').addClass('resource-panel-show')
+ $('.taskdivtable').addClass('divtable-hide')
+ $('.ts-line').addClass('divtable-hide')
+ } else if (tab_name !== 'p_resource on') {
+ $('.resource-panel').removeClass('resource-panel-show')
+ $('.taskdivtable').removeClass('divtable-hide')
+ $('.ts-line').removeClass('divtable-hide')
+ }
+ search_val = $('.search-bar .search_input').val('')
+ get_list_bytab(false);
+});
+
+$('.search-bar .search_input').on({
+ 'keyup': function (e) {
+ if (e.keyCode == 13) {
+ get_list_bytab();
+ }
+ },
+ 'blur': function () {
+ get_list_bytab(true);
+ },
+});
+
+$('.search-bar .glyphicon').click(function (e) {
+ get_list_bytab();
+});
+
+var process_list_s = 0;
+get_process_list();
+
+function setTableHead(data) {
+ $.each(Object.keys(data.meter_head), function (index, item) {
+ if (!$('.' + item).hasClass('disabled')) {
+ if (data.meter_head[item]) {
+ $('.' + item).addClass('active');
+ } else {
+ $('.' + item).removeClass('active');
+ }
+ }
+ });
+
+ $('#change_thead').bind("contextmenu", function () {
+ return false;
+ })
+ $(".plug_menu").bind("contextmenu", function () {
+ return false;
+ })
+ $('#change_thead').mousedown(function (e) {
+ e.preventDefault();
+ if (e.which == 3) { // 1 = 鼠标左键; 2 = 鼠标中键; 3 = 鼠标右键
+ var menu = $('.setting_ul');
+ var offset = $(this).offset();
+ var x = e.pageX - offset.left;
+ var y = e.pageY - offset.top;
+ var width = menu.outerWidth();
+ $(".plug_menu").removeAttr('style');
+ $(".setting_ul").removeClass('undisplay');
+ if ($('#change_thead').width() - x < width) {
+ $(".plug_menu").css({
+ position: 'absolute',
+ left: x - width + 150 + "px",
+ top: y + 50 + "px",
+ }).show();
+ } else {
+ $(".plug_menu").css({
+ position: 'absolute',
+ left: x + width + "px",
+ top: y + 50 + "px",
+ }).show();
+ }
+ }
+ $(".setting_ul").show();
+ });
+}
+
+
+$('.layui-layer').not($('.setting_ul_li')).click(function () {
+ $(".plug_menu").hide()
+ $(".setting_ul").hide();
+});
+var isProcessing = false; // 设置标志
+
+ $('.setting_ul_li').off('click').click(function (e) {
+ var that = $(this)
+ e.stopPropagation()
+ // 检查标志
+ if (isProcessing) {
+ return;
+ }
+ if (!$(this).hasClass('disabled')) {
+ isProcessing = true; // 点击事件被触发,设置标志
+ var name = $(this).attr("name")
+ clearInterval(process_list_s);
+ bt_tools.send({
+ url: 'plugin?action=a&name=task_manager&s=set_meter_head',
+ data: {meter_head_name: name}
+ }, function (data) {
+ isProcessing = false; // 操作完成,清除标志
+ if (!data) {
+ layer.msg('设置失败');
+ }
+ that.toggleClass('active')
+ get_process_list(null, null, false);
+ clearInterval(process_list_s);
+ process_list_s = setInterval(function () {
+ if ($(".t-mana").length == 0) {
+ clearInterval(process_list_s);
+ process_list_s = 0;
+ console.log('进程列表轮询任务已停止');
+ }
+ get_process_list(null, null, true);
+ }, 3000);
+ })
+ }
+ })
+
+ $('.setting_btn').on('click',function (e) {
+ e.stopPropagation()
+ var offset = $('.man-menu-sub').offset();
+ var x = e.pageX - offset.left;
+ var y = e.pageY - offset.top;
+ var width = $('.man-menu-sub').outerWidth();
+ if ($('.man-menu-sub').width() - x < width) {
+ $(".plug_menu").css({
+ position: 'absolute',
+ right: "14.5px",
+ top:"40px",
+ }).toggle();
+ $('.setting_ul').addClass('undisplay')
+ }
+ $(".setting_ul").toggle();
+ })
+
+ if (process_list_s === 0) {
+ process_list_s = setInterval(function () {
+ if ($(".t-mana").length == 0) {
+ clearInterval(process_list_s);
+ process_list_s = 0;
+ console.log('进程列表轮询任务已停止')
+ }
+ get_process_list(null, null, true);
+ }, 3000);
+ }
+
+ function get_list_bytab(isblur) {
+ if (isblur && $('.search-bar .search_input').val() === search_val) {
+ return;
+ }
+ search_val = $('.search-bar .search_input').val();
+ get_process_list();
+
+ switch (tab_name) {
+ case 'p_list':
+ $('.table_config').show();
+ $('.search-bar span').addClass('r56');
+ select_pid = ''
+ wrapPid = {}
+ canScroll2TaskMangerPossess = true
+ get_process_list();
+ break;
+ case 'p_resource':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_resource_list();
+ break;
+ case 'p_run':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_run_list();
+ break;
+ case 'p_service':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_service_list();
+ break;
+ case 'p_network':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_network_list();
+ break;
+ case 'p_user':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_user_list();
+ break;
+ case 'p_cron':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_cron_list();
+ break;
+ case 'p_session':
+ $('.table_config').hide();
+ $('.search-bar span').removeClass('r56');
+ get_who_list();
+ break;
+ }
+ }
+
+function get_process_list(sortx, reverse, rx) {
+ if ($('.t-mana .man-menu-sub .on').attr('class') != 'p_list on') return;
+ var cookie_key = 'task_process_sort';
+ var s_tmp = getCookie(cookie_key);
+ if (sortx == undefined || sortx == null) {
+ if (s_tmp) {
+ sortx_arr = s_tmp.split('|');
+ sortx = sortx_arr[0];
+ reverse = sortx_arr[1];
+ } else {
+ sortx = 'cpu_percent';
+ }
+ }
+
+ res_list = {
+ True: 'False',
+ False: 'True'
+ };
+ setCookie(cookie_key, sortx + '|' + reverse);
+ if (!rx) {
+ var loadT = layer.msg('正在获取进程列表..', {icon: 16, time: 0, shade: [0.3, '#000']})
+ }
+
+ tmPostCallback('get_process_list', {sortx: sortx,reverse: reverse,search:search_val}, function(rdata){
+ console.log(rdata);
+ if (!rx) layer.close(loadT);
+ if ($('.t-mana .man-menu-sub .on').attr('class') != 'p_list on') return;
+ if (rdata.status === false) {
+ layer.closeAll();
+ layer.msg(rdata.msg, {icon: 2});
+ return;
+ }
+ var data = rdata.data;
+
+ var year = new Date().getFullYear();
+ realProcess = [];
+ originProcess = [];
+ var list = data.process_list;
+ for (var i = 0; i < list.length; i++) {
+ list[i].haschild = false;
+ if (list[i].children && list[i].children.length > 0) {
+ list[i].haschild = true;
+ }
+ originProcess.push(list[i]);
+ realProcess.push(list[i]);
+ }
+ var selectline = buildRealProcess();
+ var tbody_tr = createProcessTable(true, data);
+ var tbody = '\
+ \
+ 应用名称 | \
+ PID | \
+ 线程 | \
+ 用户 | \
+ CPU | \
+ 内存 | \
+ io读 | \
+ io写 | \
+ 上行 | \
+ 下行 | \
+ 连接 | \
+ 状态 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '\
+
CPU:' + data.info.cpu + '%
内存:' + toSize(data.info.mem) + '
\
+
负载(load average)
' + data.info.load_average[1] + ', ' + data.info.load_average[5] + ', ' + data.info.load_average[15] + '
\
+
进程数:' + data.process_list.length + '
磁盘:' + toSize(data.info.disk) + '
\
+
';
+ $("#load_average").html(topMsg).show();
+ $(".pro_" + sortx).append('');
+ $(".table-cont").css("height", "500px");
+ scropll2selectPossess(selectline);
+ show_task();
+ setTableHead(data);
+ if(getCookie('table_config_tip')=='false'||!getCookie('table_config_tip')){
+ layer.tips('点击可设置表头', '.setting_btn', {
+ tips: [1, '#20a53a'],
+ time: 3000
+ });
+ setCookie('table_config_tip',true);
+ }
+ // 清除掉之前绑定的滚动事件
+ $("#table-cont").unbind('scroll');
+ // 重新绑定滚动事件
+ $('#table-cont').scroll(task_manager_possess_scroll());
+ });
+}
+
+function task_manager_possess_scroll() {
+ var timer = null;
+ var set2selected = null
+ // 滚动节流
+ return function () {
+ if (timer !== null) return
+ timer = setTimeout(function () {
+ timer = null
+ canScroll2TaskMangerPossess = false
+ if (set2selected !== null) clearTimeout(set2selected)
+ // 最后一次滚动后2秒内不再滚动,才能滚动到选中的行
+ set2selected = setTimeout(function () {
+ canScroll2TaskMangerPossess = true
+ }, 2000)
+ }, 500)
+ }
+}
+
+function scropll2selectPossess(selectline) {
+ if (canScroll2TaskMangerPossess && selectline !== -1) {
+ var top = $('#table-cont')[0].scrollTop;
+ // if(selectline > 2)
+ if (selectline * 38 > top + 500 || selectline * 38 < top) {
+ $('#table-cont')[0].scrollTo(0, (selectline - 2) * 38, 'smooth');
+ }
+ }
+}
+
+function show_process_child(pid) {
+ wrapPid[pid + ''] = true;
+ // buildRealProcess()
+ // createProcessTable()
+}
+
+function colp_process_child(pid) {
+ // select_pid = pid+'';
+ wrapPid[pid + ''] = false;
+ // buildRealProcess()
+ // createProcessTable()
+}
+
+function click_process_tr(e, pid, fpid) {
+ select_pid = pid + '';
+ if (e.target.innerText === '结束' && fpid) {
+ select_pid = fpid + '';
+ }
+ var selectline = buildRealProcess()
+ createProcessTable()
+ scropll2selectPossess(selectline)
+}
+
+// 构建真实进程列表
+function buildRealProcess() {
+ realProcess = [];
+ var len = originProcess.length;
+ for (var i = 0; i < len; i++) {
+ realProcess.push(originProcess[i]);
+ if (wrapPid[originProcess[i].pid + '']) {
+ // console.log(originProcess[i]);
+ if (!originProcess[i].children) {
+ wrapPid[originProcess[i].pid + ''] = false;
+ continue;
+ }
+ var childSelected = false;
+ for (var j = 0; j < originProcess[i].children.length; j++) {
+ originProcess[i].children[j].fpid = originProcess[i].pid + ''
+ originProcess[i].children[j].ischild = true
+ originProcess[i].children[j].isselect = false
+ if (originProcess[i].pid + '' === select_pid) {
+ originProcess[i].children[j].isselect = true
+ }
+ if (originProcess[i].children[j].pid + '' === select_pid) {
+ var childSelected = true;
+ }
+ realProcess.push(originProcess[i].children[j]);
+ // 显示选中的父子进程
+ }
+ if (childSelected) {
+ for (var k = 0; k <= originProcess[i].children.length; k++) {
+ realProcess.pop()
+ }
+ originProcess[i].isselect = true
+ realProcess.push(originProcess[i])
+ for (var l = 0; l < originProcess[i].children.length; l++) {
+ originProcess[i].children[l].isselect = true
+ realProcess.push(originProcess[i].children[l]);
+ }
+ }
+ }
+ }
+ for (var i = 0; i < realProcess.length; i++) {
+ if (realProcess[i].pid + '' === select_pid) {
+ return i// 返回选中的下标
+ }
+ }
+ return -1
+}
+
+// 生成进程表格内容
+function createProcessTable(getboday, data) {
+ console.log('createProcessTable',getboday, data);
+ console.log('realProcess',realProcess);
+ var tbody_tr = '';
+ for (var i = 0; i < realProcess.length; i++) {
+ if (realProcess[i].status == '活动') realProcess[i].status = '活动';
+ var colp = realProcess[i].haschild ? '' : '';
+ if (wrapPid[realProcess[i].pid + '']) {
+ colp = '';
+ }
+ var childNums = realProcess[i].haschild ? '(' + realProcess[i].children.length + ')' : '';
+ var namewidth = "max-width:120px;"
+ if (realProcess[i].ischild) {
+ namewidth = "max-width:80px;"
+ }
+ if (realProcess[i].haschild) {
+ namewidth = "max-width:100px;"
+ }
+ var processName = '' + realProcess[i].ps + '';
+ var isProcessChild = realProcess[i].ischild ? 'process-child' : '';
+ var childStyle = realProcess[i].ischild ? 'width:100px' : '';
+ var selected = realProcess[i].pid + '' === select_pid || realProcess[i].isselect ? 'class="process-select"' : '';
+ var selected_one = realProcess[i].pid + '' === select_pid ? 'style="background-color:#F6F6F6;"' : '';
+ var kill_process = realProcess[i].haschild ? 'kill_process_all' : 'kill_process';
+
+ var tbody_td = '';
+ if ('io_read_bytes' in realProcess[i]){
+ tbody_td =+ '' + toSize(realProcess[i].io_read_speed).replace(' ', '') + ' | ';
+ tbody_td =+ '' + toSize(realProcess[i].io_write_speed).replace(' ', '') + ' | ';
+ }
+
+ // ' + ToSize(realProcess[i].up).replace(' ', '') + ' | \
+ // ' + ToSize(realProcess[i].down).replace(' ', '') + ' | \
+ tbody_tr += '\
+ \
+ ' + colp + '\
+ \
+ ' + processName + '\
+ ' + childNums + '\
+ | \
+ ' + realProcess[i].pid + ' | \
+ ' + realProcess[i].threads + ' | \
+ ' + realProcess[i].user + ' | \
+ ' + realProcess[i].cpu_percent + '% | \
+ ' + toSize(realProcess[i].memory_used).replace(' ', '') + ' | \
+ '+tbody_td+'\
+ ' + realProcess[i].connects + ' | \
+ ' + realProcess[i].status + ' | \
+ 结束 | \
+
';
+ }
+ if (getboday) return tbody_tr;
+ $("#TaskManagement tbody").html(tbody_tr);
+}
+
+// 获取资源列表
+function get_resource_list() {
+ // console.log('get_resource_list----------');
+ var url = '/plugin?action=a&name=task_manager&s=cpu_status'
+ // url = 'plugin?action=a&name=task_manager&s=get_disk_staus'
+
+ var res_list = {
+ True: 'False',
+ False: 'True'
+ }
+ var reverse = 'True'
+ $.post(url, function (data) {
+ console.log(data);
+ realProcess = []
+ originProcess = []
+ var list = data.process_list
+ for (var i = 0; i < list.length; i++) {
+ list[i].haschild = false
+ if (list[i].children && list[i].children.length > 0) {
+ list[i].haschild = true
+ }
+ originProcess.push(list[i])
+ realProcess.push(list[i])
+ }
+ // console.log('realllll');
+
+ buildRealProcess()
+ var tbody_tr = createProcessTable(true)
+ var tbody = '\
+ \
+ 应用名称 | \
+ PID | \
+ 线程 | \
+ 用户 | \
+ CPU | \
+ 内存 | \
+ io读 | \
+ io写 | \
+ 上行 | \
+ 下行 | \
+ 连接 | \
+ 状态 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + ''
+ $('#taskResourceTable').html(tbody);
+ $(".table-cont").css("height", "220px");
+ })
+
+ $("#load_average").html('')
+}
+
+//查看计划任务列表
+function get_cron_list() {
+ var loadT = layer.msg('获取计划任务列表..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_cron_list', {search:search_val}, function(rdata){
+ layer.close(loadT);
+ var tbody_tr = '';
+ for (var i = 0; i < rdata.length; i++) {
+ tbody_tr += '\
+ ' + rdata[i].cycle + ' | \
+ ' + rdata[i].exe + ' | \
+ ' + rdata[i].ps + ' | \
+ 删除 | \
+
';
+ }
+ var tbody = '\
+ \
+ 周期 | \
+ 执行 | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '';
+ $("#load_average").html(topMsg).hide();
+ $(".table-cont").css("height", "597px");
+ show_task();
+ });
+}
+
+
+//查看网络状态
+function get_network_list(rflush) {
+ var loadT = layer.msg(lan.public.the_get, {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_network_list', {search:search_val}, function(rdata){
+ layer.close(loadT);
+ if (rdata.data['is_mac']){
+ tbody_tr += "mac无法使用 |
";
+ tbody = "\
+ \
+ " + lan.index.net_protocol + " | \
+ " + lan.index.net_address_dst + " | \
+ " + lan.index.net_address_src + " | \
+ " + lan.index.net_address_status + "? | \
+ " + lan.index.net_process + " | \
+ " + lan.index.net_process_pid + " | \
+
\
+ \
+ " + tbody_tr + "";
+ $("#TaskManagement").html(tbody);
+ show_task();
+ return;
+ }
+
+ console.log(rdata);
+
+ var tbody_tr = "";
+ for (var i = 0; i < rdata.list.length; i++) {
+ tbody_tr += ""
+ + "" + rdata.list[i].type + " | "
+ + "" + rdata.list[i].laddr[0] + ":" + rdata.list[i].laddr[1] + " | "
+ + "" + (rdata.list[i].raddr.length > 1 ? "" + rdata.list[i].raddr[0] + ":" + rdata.list[i].raddr[1] : 'NONE') + " | "
+ + "" + rdata.list[i].status + " | "
+ + "" + rdata.list[i].process + " | "
+ + "" + rdata.list[i].pid + " | "
+ + "
";
+ }
+
+ tbody = "\
+ \
+ " + lan.index.net_protocol + " | \
+ " + lan.index.net_address_dst + " | \
+ " + lan.index.net_address_src + " | \
+ " + lan.index.net_address_status + "? | \
+ " + lan.index.net_process + " | \
+ " + lan.index.net_process_pid + " | \
+
\
+ \
+ " + tbody_tr + "";
+
+ $("#TaskManagement").html(tbody);
+ var topMsg = '\
+
\
+
总发送:' + toSize(rdata.state.upTotal) + '
\
+
总接收:' + toSize(rdata.state.downTotal) + '
\
+
\
+
\
+
上行:' + toSize(rdata.state.up) + '
\
+
下行:' + toSize(rdata.state.down) + '
\
+
\
+
\
+
总发包:' + to_max(rdata.state.upPackets) + '
\
+
总收包:' + to_max(rdata.state.downPackets) + '
\
+
\
+
\
+
包发送/秒:' + to_max(rdata.state.upPackets_s) + '
\
+
包接收/秒:' + to_max(rdata.state.downPackets_s) + '
\
+
\
+
';
+ $("#load_average").html(topMsg).show();
+ $(".table-cont").css("height", "500px");
+ show_task();
+ });
+}
+
+function to_max(num) {
+ if (num > 10000) {
+ num = num / 10000;
+ if (num > 10000) {
+ num = num / 10000;
+ return num.toFixed(5) + ' 亿';
+ }
+ return num.toFixed(5) + ' 万';
+ }
+ return num;
+}
+
+//获取会话列表
+function get_who_list() {
+ var loadT = layer.msg('正在获取用户会话列表..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_who', {search:search_val}, function(data){
+ layer.close(loadT);
+ var rdata = data.data;
+ var tbody_tr = '';
+ for (var i = 0; i < rdata.length; i++) {
+ tbody_tr += '\
+ ' + rdata[i].user + ' | \
+ ' + rdata[i].pts + ' | \
+ ' + rdata[i].ip + ' | \
+ ' + rdata[i].date + ' | \
+ 强制断开 | \
+
';
+ }
+ var tbody = '\
+ \
+ 用户 | \
+ PTS | \
+ 登陆IP | \
+ 登陆时间 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '';
+ $("#load_average").html(topMsg).hide();
+ $(".table-cont").css("height", "597px");
+ show_task();
+ });
+}
+
+//获取启动列表
+function get_run_list() {
+ var loadT = layer.msg('正在获取启动项列表..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_run_list', {search:search_val}, function(rdata){
+ layer.close(loadT);
+ if (rdata.data['is_mac']){
+ tbody_tr += "mac无法使用 |
";
+ var tbody = '\
+ \
+ 名称 | \
+ 启动路径 | \
+ 文件大小 | \
+ 文件权限 | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ return;
+ }
+
+
+ var tbody_tr = '';
+ for (var i = 0; i < rdata.run_list.length; i++) {
+ tbody_tr += '\
+ ' + rdata.run_list[i].name + ' | \
+ ' + rdata.run_list[i].srcfile + ' | \
+ ' + toSize(rdata.run_list[i].size) + ' | \
+ ' + rdata.run_list[i].access + ' | \
+ ' + rdata.run_list[i].ps + ' | \
+ 编辑 | \
+
';
+ }
+ var tbody = '\
+ \
+ 名称 | \
+ 启动路径 | \
+ 文件大小 | \
+ 文件权限 | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '当前运行级别: level-' + rdata.run_level + '
? ';
+ $("#load_average").html(topMsg).show();
+ $(".table-cont").css("height", "500px");
+ show_task();
+ });
+}
+
+//获取服务列表
+function get_service_list() {
+ var loadT = layer.msg('正在获取服务列表..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_service_list', {search:search_val}, function(rdata){
+ layer.close(loadT);
+
+ if (rdata.data['is_mac']){
+ tbody_tr += "mac无法使用 |
";
+ var tbody = '\
+ \
+ 名称 | \
+ Level-0 | \
+ Level-1 | \
+ Level-2 | \
+ Level-3 | \
+ Level-4 | \
+ Level-5 | \
+ Level-6 | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ return;
+ }
+
+ var tbody_tr = '';
+ for (var i = 0; i < rdata.serviceList.length; i++) {
+ tbody_tr += '\
+ ' + rdata.serviceList[i].name + ' | \
+ ' + rdata.serviceList[i].runlevel_0 + ' | \
+ ' + rdata.serviceList[i].runlevel_1 + ' | \
+ ' + rdata.serviceList[i].runlevel_2 + ' | \
+ ' + rdata.serviceList[i].runlevel_3 + ' | \
+ ' + rdata.serviceList[i].runlevel_4 + ' | \
+ ' + rdata.serviceList[i].runlevel_5 + ' | \
+ ' + rdata.serviceList[i].runlevel_6 + ' | \
+ ' + rdata.serviceList[i].ps + ' | \
+ 删除 | \
+
';
+ }
+ var tbody = '\
+ \
+ 名称 | \
+ Level-0 | \
+ Level-1 | \
+ Level-2 | \
+ Level-3 | \
+ Level-4 | \
+ Level-5 | \
+ Level-6 | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '当前运行级别: level-' + rdata.runlevel + '
? ';
+ $("#load_average").html(topMsg).show();
+ $(".table-cont").css("height", "500px");
+ show_task();
+ });
+}
+
+//取用户列表
+function get_user_list() {
+ var loadT = layer.msg('正在获取用户列表..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_user_list', {search:search_val}, function(data){
+ layer.close(loadT);
+ var rdata = data.data;
+ var tbody_tr = '';
+ for (var i = 0; i < rdata.length; i++) {
+ tbody_tr += '\
+ ' + rdata[i].username + ' | \
+ ' + rdata[i].home + ' | \
+ ' + rdata[i].group + ' | \
+ ' + rdata[i].uid + ' | \
+ ' + rdata[i].gid + ' | \
+ ' + rdata[i].login_shell + ' | \
+ ' + rdata[i].ps + ' | \
+ 删除 | \
+
';
+ }
+ var tbody = '\
+ \
+ 用户名 | \
+ home | \
+ 用户组 | \
+ uid | \
+ gid | \
+ 登陆脚本? | \
+ 描述 | \
+ 操作 | \
+
\
+ \
+ ' + tbody_tr + '';
+ $("#TaskManagement").html(tbody);
+ var topMsg = '';
+ $("#load_average").html(topMsg).hide();
+ $(".table-cont").css("height", "597px");
+ show_task();
+ });
+}
+
+//删除用户
+function userdel(user) {
+ safeMessage('删除用户【' + user + '】', '删除后可能导致您的环境无法正常运行,继续吗?', function () {
+ var loadT = layer.msg('正在删除用户[' + user + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=remove_user', {user: user}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_user_list();
+ });
+ });
+}
+
+//结束进程
+function kill_process(pid, fpid) {
+ if (fpid) {
+ select_pid = fpid;
+ }
+ var w = layer.confirm('您是否要结束 (' + pid + ') 进程?', {
+ btn: ['结束', '取消'], //按钮
+ title: '结束' + pid,
+ closeBtn: 2
+ }, function () {
+ var loadT = layer.msg('正在结束进程[' + pid + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=kill_process', {pid: pid}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_process_list();
+ })
+ }, function () {
+ layer.close(w)
+ })
+}
+
+//结束进程树
+function kill_process_all(pid) {
+ var w = layer.confirm('您是否要结束 (' + pid + ') 进程?', {
+ btn: ['结束', '取消'], //按钮
+ title: '结束' + pid,
+ closeBtn: 2
+ }, function () {
+ var loadT = layer.msg('正在结束父进程[' + pid + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=kill_process_all', {pid: pid}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_process_list();
+ })
+ }, function () {
+ layer.close(w)
+ })
+}
+
+//打开文件所在位置
+function open_path(path) {
+ tmp = path.split('/')
+ tmp[tmp.length - 1] = '';
+ path = '/' + tmp.join('/');
+ openPath(path);
+}
+
+//删除服务
+function remove_service(serviceName) {
+ SafeMessage('删除服务【' + serviceName + '】', '删除后可能导致您的环境无法正常运行,继续吗?', function () {
+ var loadT = layer.msg('正在删除服务[' + serviceName + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=remove_service', {serviceName: serviceName}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_service_list();
+ });
+ });
+}
+
+//在线编辑文件
+function online_edit_file(fileName) {
+ onlineEditFile(0, fileName);
+}
+
+//删除计划任务
+function remove_cron(index) {
+ safeMessage('删除计划任务[' + index + ']', '删除后将无法恢复,继续吗?', function () {
+ var loadT = layer.msg('正在删除计划任务..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=remove_cron', {index: index}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_cron_list();
+ });
+ });
+}
+
+//强制断开会话
+function pkill_session(pts) {
+ safeMessage('强制断开会话[' + pts + ']', '强制断开此会话吗?', function () {
+ var loadT = layer.msg('正在断开会话..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=pkill_session', {pts: pts}, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_who_list();
+ });
+ });
+}
+
+//设置服务启动级别状态
+function set_runlevel_state(runlevel, serviceName) {
+ var loadT = layer.msg('正在设置服务[' + serviceName + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/plugin?action=a&name=task_manager&s=set_runlevel_state', {
+ runlevel: runlevel,
+ serviceName: serviceName
+ }, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ if (rdata.status) get_service_list();
+ });
+}
+
+//查看进程详情
+function get_process_info(pid) {
+ var loadT = layer.msg('正在获取进程信息[' + pid + ']..', {icon: 16, time: 0, shade: [0.3, '#000']});
+ tmPostCallback('get_process_info', {pid:pid}, function(data){
+ console.log('get_process_info',data);
+ layer.close(loadT);
+ var rdata = data.data;
+ fileBody = '';
+ for (var i = 0; i < rdata.open_files.length; i++) {
+ fileBody += '' + rdata.open_files[i].path + ' | \
+ ' + rdata.open_files[i].mode + ' | \
+ ' + rdata.open_files[i].position + ' | \
+ ' + rdata.open_files[i].flags + ' | \
+ ' + rdata.open_files[i].fd + ' | \
+
';
+ }
+ var cbody = '\
+
\
+
\
+ \
+ \
+ 名称 | ' + rdata.name + ' | \
+ PID | ' + rdata.pid + ' | \
+ 状态 | ' + rdata.status + ' | \
+
\
+ \
+ 父进程 | ' + rdata.pname + '(' + rdata.ppid + ') | \
+ 用户 | ' + rdata.user + ' | \
+ 线程 | ' + rdata.threads + ' | \
+
\
+ \
+ Socket | ' + rdata.connects + ' | \
+ io读 | ' + toSize(rdata.io_read_bytes) + ' | \
+ io写 | ' + toSize(rdata.io_write_bytes) + ' | \
+
\
+ \
+ 启动时间 | ' + getLocalTime(rdata.create_time) + ' | \
+ 描述 | ' + rdata.ps + ' | \
+
\
+ \
+ 启动命令 | ' + rdata.comline.join(" ") + ' | \
+
\
+ \
+
\
+
\
+
内存
\
+
\
+
\
+ \
+ \
+ rss | ' + toSize(rdata.memory_full.rss) + ' | \
+ pss | ' + toSize(rdata.memory_full.pss) + ' | \
+ uss | ' + toSize(rdata.memory_full.uss) + ' | \
+
\
+ \
+ vms | ' + toSize(rdata.memory_full.vms) + ' | \
+ swap | ' + toSize(rdata.memory_full.swap) + ' | \
+ shared | ' + toSize(rdata.memory_full.shared) + ' | \
+
\
+ \
+ data | ' + toSize(rdata.memory_full.data) + ' | \
+ text | ' + toSize(rdata.memory_full.text) + ' | \
+ dirty | ' + toSize(rdata.memory_full.dirty) + ' | \
+
\
+ \
+
\
+
\
+
打开的文件列表
\
+
\
+
\
+
\
+ \
+ \
+ 文件 | \
+ mode | \
+ position | \
+ flags | \
+ fd | \
+
\
+ \
+ ' + fileBody + '\
+
\
+
\
+
\
+
\
+ \
+ \
+ \
+
';
+
+ TaskProcessLayerIndex = layer.open({
+ type: 1,
+ title: '进程属性[' + rdata.name + '] -- ' + rdata.exe,
+ area: '750px',
+ closeBtn: 2,
+ shadeClose: false,
+ content: cbody
+ });
+ show_jc_flie();
+ });
+}
+
+//屏蔽指定IP
+function dropAddress(address) {
+ layer.confirm(lan.index.net_doup_ip_msg, {icon: 3, closeBtn: 2}, function () {
+ loadT = layer.msg(lan.index.net_doup_ip_to, {icon: 16, time: 0, shade: [0.3, '#000']});
+ $.post('/firewall?action=AddDropAddress', 'port=' + address + '&ps=' + lan.index.net_doup_ip_ps, function (rdata) {
+ layer.close(loadT);
+ layer.msg(rdata.msg, {icon: rdata.status ? 1 : 2});
+ });
+ });
+}
+
+function show_task() {
+ $(".ts-line").width($("#TaskManagement").width());
+ $("#TaskManagement tbody td").click(function () {
+ // console.log('---');
+ $(this).parents("tr").addClass("active").siblings().removeClass("active");
+ });
+ var tableCont = document.querySelector('#table-cont');
+ //表格固定
+ var sct = tableCont.scrollTop;
+ tableCont.querySelector('thead').style.transform = 'translateY(' + sct + 'px)';
+ tableCont.addEventListener('scroll', scrollHandle);
+}
+
+function show_jc_flie() {
+ var tableJc = document.querySelector('#jc-file-table');
+ //文件表格固定
+ tableJc.addEventListener('scroll', scrollHandle);
+}
+
+function scrollHandle(e) {
+ var scrollTop = this.scrollTop;
+ this.querySelector('thead').style.transform = 'translateY(' + scrollTop + 'px)';
+}
+
+var masterPluginTitle = $('.TaskManView').parents('.layui-layer');
+// masterPluginTitle.append('');
+masterPluginTitle.on('click', '.bt-desired', function(){
+ bt_tools.nps({name:'任务管理器',type:26})
+})
\ No newline at end of file
diff --git a/plugins/task_manager/process_network_total.py b/plugins/task_manager/process_network_total.py
new file mode 100644
index 000000000..cd317721c
--- /dev/null
+++ b/plugins/task_manager/process_network_total.py
@@ -0,0 +1,318 @@
+#coding: utf-8
+#-------------------------------------------------------------------
+# 宝塔Linux面板
+#-------------------------------------------------------------------
+# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
+#-------------------------------------------------------------------
+# Author: hwliang
+#-------------------------------------------------------------------
+
+import sys
+import time
+import os
+import struct
+
+os.chdir('/www/server/panel')
+if 'class/' in sys.path: sys.path.insert(0,"class/")
+import copy
+try:
+ import pcap
+except ImportError:
+ if os.path.exists('/usr/bin/apt'):
+ os.system("apt install libpcap-dev -y")
+ elif os.path.exists('/usr/bin/dnf'):
+ red_file = '/etc/redhat-release'
+ if os.path.exists(red_file):
+ f = open(red_file,'r')
+ red_body = f.read()
+ f.close()
+ if red_body.find('CentOS Linux release 8.') != -1:
+ rpm_file = '/root/libpcap-1.9.1.rpm'
+ down_url = "wget -O {} https://repo.almalinux.org/almalinux/8/PowerTools/x86_64/os/Packages/libpcap-devel-1.9.1-5.el8.x86_64.rpm --no-check-certificate -T 10".format(rpm_file)
+ print(down_url)
+ os.system(down_url)
+ os.system("rpm -ivh {}".format(rpm_file))
+ if os.path.exists(rpm_file): os.remove(rpm_file)
+ else:
+ os.system("dnf install libpcap-devel -y")
+ else:
+ os.system("dnf install libpcap-devel -y")
+ elif os.path.exists('/usr/bin/yum'):
+ os.system("yum install libpcap-devel -y")
+
+ os.system("btpip install pypcap")
+ try:
+ import pcap
+ except ImportError:
+ print("pypcap module install failed.")
+ sys.exit()
+
+class process_network_total:
+ __pid_file = 'logs/process_network_total.pid'
+ __inode_list = {}
+ __net_process_list = {}
+ __net_process_size = {}
+ __last_stat = 0
+ __last_write_time = 0
+ __end_time = 0
+
+ def start(self,timeout = 0):
+ '''
+ @name 启动进程网络监控
+ @author hwliang<2021-09-13>
+ @param timeout 结束时间(秒),0表示持久运行,默认为0
+ @return void
+ '''
+ stime = time.time()
+ self.__end_time = timeout + stime
+ self.__last_stat = stime
+ try:
+ p = pcap.pcap() # 监听所有网卡
+ p.setfilter('tcp') # 只监听TCP数据包
+ for p_time,p_data in p:
+ self.handle_packet(p_data)
+ # 过期停止监听
+ if timeout > 0:
+ if p_time > self.__end_time:
+ self.rm_pid_file()
+ break
+ except:
+ self.rm_pid_file()
+
+ def handle_packet(self, pcap_data):
+ '''
+ @name 处理pcap数据包
+ @author hwliang<2021-09-12>
+ @param pcap_data pcap数据包
+ @return void
+ '''
+ # 获取IP协议头
+ ip_header = pcap_data[14:34]
+ # 解析src/dst地址
+ src_ip = ip_header[12:16]
+ dst_ip = ip_header[16:20]
+ # 解析sport/dport端口
+ src_port = pcap_data[34:36]
+ dst_port = pcap_data[36:38]
+
+ src = src_ip + b':' + src_port
+ dst = dst_ip + b':' + dst_port
+ # 计算数据包长度
+ pack_size = len(pcap_data)
+ # 统计进程流量
+ self.total_net_process(dst,src,pack_size)
+
+ def total_net_process(self,dst,src,pack_size):
+ '''
+ @name 统计进程流量
+ @author hwliang<2021-09-13>
+ @param dst 目标地址
+ @param src 源地址
+ @param pack_size 数据包长度
+ @return void
+ '''
+ self.get_tcp_stat()
+ direction = None
+ mtime = time.time()
+ if dst in self.__net_process_list:
+ pid = self.__net_process_list[dst]
+ direction = 'down'
+ elif src in self.__net_process_list:
+ pid = self.__net_process_list[src]
+ direction = 'up'
+ else:
+ if mtime - self.__last_stat > 3:
+ self.__last_stat = mtime
+ self.get_tcp_stat(True)
+ if dst in self.__net_process_list:
+ pid = self.__net_process_list[dst]
+ direction = 'down'
+ elif src in self.__net_process_list:
+ pid = self.__net_process_list[src]
+ direction = 'up'
+
+ if not direction: return False
+ if not pid: return False
+ if not pid in self.__net_process_size:
+ self.__net_process_size[pid] = {}
+ self.__net_process_size[pid]['down'] = 0
+ self.__net_process_size[pid]['up'] = 0
+ self.__net_process_size[pid]['up_package'] = 0
+ self.__net_process_size[pid]['down_package'] = 0
+
+ self.__net_process_size[pid][direction] += pack_size
+ self.__net_process_size[pid][direction + '_package'] += 1
+
+ # 写入到文件
+ if mtime - self.__last_write_time > 1:
+ self.__last_write_time = mtime
+ self.write_net_process()
+
+ def write_net_process(self):
+ '''
+ @name 写入进程流量
+ @author hwliang<2021-09-13>
+ @return void
+ '''
+ w_file = '/dev/shm/bt_net_process'
+ process_size = copy.deepcopy(self.__net_process_size)
+ net_process = []
+ for pid in process_size.keys():
+ net_process.append(str(pid) + " " + str(process_size[pid]['down']) + " " + str(process_size[pid]['up']) + " " + str(process_size[pid]['down_package']) + " " + str(process_size[pid]['up_package']))
+
+ f = open(w_file,'w+',encoding='utf-8')
+ f.write('\n'.join(net_process))
+ f.close()
+
+ def hex_to_ip(self, hex_ip):
+ '''
+ @name 将16进制的IP地址转换为字符串IP地址
+ @author hwliang<2021-09-13>
+ @param hex_ip 16进制的IP地址:16进程端口
+ @return tuple(ip,port) IP地址,端口
+ '''
+ hex_ip,hex_port = hex_ip.split(':')
+ ip = '.'.join([str(int(hex_ip[i:i+2], 16)) for i in range(0, len(hex_ip), 2)][::-1])
+ port = int(hex_port, 16)
+ return ip,port
+
+ def get_tcp_stat(self,force = False):
+ '''
+ @name 获取当前TCP连接状态表
+ @author hwliang<2021-09-13>
+ @param force 是否强制刷新
+ @return dict
+ '''
+ if not force and self.__net_process_list: return self.__net_process_list
+ self.__net_process_list = {}
+ tcp_stat_file = '/proc/net/tcp'
+ tcp_stat = open(tcp_stat_file, 'rb')
+ tcp_stat_list = tcp_stat.read().decode('utf-8').split('\n')
+ tcp_stat.close()
+ tcp_stat_list = tcp_stat_list[1:]
+ if force: self.get_process_inodes(force)
+ for i in tcp_stat_list:
+ tcp_tmp = i.split()
+ if len(tcp_tmp) < 10: continue
+ inode = tcp_tmp[9]
+ if inode == '0': continue
+ local_ip,local_port = self.hex_to_ip(tcp_tmp[1])
+ if local_ip == '127.0.0.1': continue
+ remote_ip,remote_port = self.hex_to_ip(tcp_tmp[2])
+ if local_ip == remote_ip: continue
+ if remote_ip == '0.0.0.0': continue
+
+ pid = self.inode_to_pid(inode,force)
+ if not pid: continue
+
+ key = self.get_ip_pack(local_ip) + b':' + self.get_port_pack(local_port)
+ self.__net_process_list[key] = pid
+ return self.__net_process_list
+
+
+ def get_port_pack(self,port):
+ '''
+ @name 将端口转换为字节流
+ @author hwliang<2021-09-13>
+ @param port 端口
+ @return bytes
+ '''
+ return struct.pack('H',int(port))[::-1]
+
+ def get_ip_pack(self,ip):
+ '''
+ @name 将IP地址转换为字节流
+ @author hwliang<2021-09-13>
+ @param ip IP地址
+ @return bytes
+ '''
+ ip_arr = ip.split('.')
+ ip_pack = b''
+ for i in ip_arr:
+ ip_pack += struct.pack('B',int(i))
+ return ip_pack
+
+ def inode_to_pid(self,inode,force = False):
+ '''
+ @name 将inode转换为进程ID
+ @author hwliang<2021-09-13>
+ @param inode inode
+ @param force 是否强制刷新
+ @return int
+ '''
+ inode_list = self.get_process_inodes()
+ if inode in inode_list:
+ return inode_list[inode]
+ return None
+
+ def get_process_inodes(self,force = False):
+ '''
+ @name 获取进程inode列表
+ @author hwliang<2021-09-13>
+ @param force 是否强制刷新
+ @return dict
+ '''
+ if not force and self.__inode_list: return self.__inode_list
+ proc_path = '/proc'
+ inode_list = {}
+ for pid in os.listdir(proc_path):
+ try:
+ if not pid.isdigit(): continue
+ inode_path = proc_path + '/' + pid + '/fd'
+ for fd in os.listdir(inode_path):
+ try:
+ fd_file = inode_path + '/' + fd
+ fd_link = os.readlink(fd_file)
+ if fd_link.startswith('socket:['):
+ inode = fd_link[8:-1]
+ inode_list[inode] = pid
+ except:
+ continue
+ except:
+ continue
+ self.__inode_list = inode_list
+ return inode_list
+
+ def get_process_name(self,pid):
+ '''
+ @name 获取进程名称
+ @author hwliang<2021-09-13>
+ @param pid 进程ID
+ @return str
+ '''
+ pid_path = '/proc/' + pid + '/comm'
+ if not os.path.exists(pid_path): return ''
+ pid_file = open(pid_path, 'rb')
+ pid_name = pid_file.read().decode('utf-8').strip()
+ pid_file.close()
+ return pid_name
+
+
+ def write_pid(self):
+ '''
+ @name 写入进程ID到PID文件
+ @author hwliang<2021-09-13>
+ @return void
+ '''
+ self_pid = os.getpid()
+ pid_file = open(self.__pid_file,'w')
+ pid_file.write(str(self_pid))
+ pid_file.close()
+
+ def rm_pid_file(self):
+ '''
+ @name 删除进程pid文件
+ @author hwliang<2021-09-13>
+ @return void
+ '''
+ if os.path.exists(self.__pid_file):
+ os.remove(self.__pid_file)
+
+if __name__ == '__main__':
+ if len(sys.argv) > 1:
+ timeout = int(sys.argv[-1])
+ else:
+ timeout = 0
+ p = process_network_total()
+ p.write_pid()
+ p.start(timeout)
\ No newline at end of file
diff --git a/plugins/task_manager/task_manager_index.py b/plugins/task_manager/task_manager_index.py
new file mode 100755
index 000000000..230b5d114
--- /dev/null
+++ b/plugins/task_manager/task_manager_index.py
@@ -0,0 +1,1182 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import re
+import threading
+import psutil
+import json
+
+from typing import List, Dict
+
+sys.path.append(os.getcwd() + "/class/core")
+import mw
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+def getPluginName():
+ return 'task_manager'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+class mainClass(object):
+
+ pids = None
+
+ new_info = {}
+ old_info = {}
+ new_net_info = {}
+ old_net_info = {}
+ old_path = '/www/server/task_manager/task_old.json'
+ old_net_path = '/www/server/task_manager/network_old.json'
+ panel_pid = None
+ task_pid = None
+ __process_net_list = {}
+ __cpu_time = None
+
+ meter_head = {}
+
+ last_net_process = None
+ last_net_process_time = 0
+
+ # lock
+ _instance_lock = threading.Lock()
+ is_mac = False
+
+ def __init__(self):
+ # print("__init__")
+ self.is_mac = mw.isAppleSystem()
+ self.old_path = getServerDir()+'/task_old.json'
+ self.old_net_path = getServerDir()+'/network_old.json'
+
+ self.old_info['cpu_time'] = self.get_cpu_time()
+ self.old_info['time'] = time.time()
+
+ @classmethod
+ def instance(cls, *args, **kwargs):
+ if not hasattr(mainClass, "_instance"):
+ with mainClass._instance_lock:
+ if not hasattr(mainClass, "_instance"):
+ mainClass._instance = mainClass(*args, **kwargs)
+ return mainClass._instance
+
+ def get_old(self):
+ if self.old_info: return True
+ # if not os.path.exists(self.old_path): return False
+ data = cache.get(self.old_path)
+ if not data: return False
+ # data = json.loads(data)
+ if not data: return False
+ self.old_info = data
+ del (data)
+ return True
+
+ def get_net_old(self):
+ if self.old_net_info: return True
+ # if not os.path.exists(self.old_net_path): return False
+ data = cache.get(self.old_net_path)
+ if not data: return False
+ # data = json.loads(data)
+ if not data: return False
+ self.old_net_info = data
+ del (data)
+ return True
+
+ def get_process_net_list(self):
+ w_file = '/dev/shm/bt_net_process'
+ if not os.path.exists(w_file): return
+ self.last_net_process = cache.get('net_process')
+ self.last_net_process_time = cache.get('last_net_process')
+ net_process_body = public.readFile(w_file)
+ if not net_process_body: return
+ net_process = net_process_body.split('\n')
+ for np in net_process:
+ if not np: continue
+ tmp = {}
+ np_list = np.split()
+ if len(np_list) < 5: continue
+ tmp['pid'] = int(np_list[0])
+ tmp['down'] = int(np_list[1])
+ tmp['up'] = int(np_list[2])
+ tmp['down_package'] = int(np_list[3])
+ tmp['up_package'] = int(np_list[4])
+ self.__process_net_list[tmp['pid']] = tmp
+ cache.set('net_process', self.__process_net_list, 600)
+ cache.set('last_net_process', time.time(), 600)
+
+ # 获取进程连接数
+ def get_connects(self, pid):
+ connects = 0
+ try:
+ if pid == 1: return connects
+ tp = '/proc/' + str(pid) + '/fd/'
+ if not os.path.exists(tp): return connects
+ for d in os.listdir(tp):
+ fname = tp + d
+ if os.path.islink(fname):
+ l = os.readlink(fname)
+ if l.find('socket:') != -1: connects += 1
+ except:
+ pass
+ return connects
+
+ def get_mem_info(self, get=None):
+ mem = psutil.virtual_memory()
+ if self.is_mac:
+ memInfo = {'memTotal': mem.total}
+ memInfo['memRealUsed'] = memInfo['memTotal'] * (mem.percent / 100)
+ return memInfo['memRealUsed']
+
+ memInfo = {'memTotal': mem.total, 'memFree': mem.free, 'memBuffers': mem.buffers, 'memCached': mem.cached}
+ memInfo['memRealUsed'] = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached']
+ return memInfo['memRealUsed']
+
+ # 进程备注,name,pid,启动命令
+ def get_process_ps(self, name, pid, p_exe=None, p=None):
+ processPs = {
+ 'irqbalance': '系统进程-优化系统性能服务',
+ 'containerd': 'docker管理服务',
+ 'qmgr': '系统进程-管理和控制邮件进程',
+ 'pickup': '系统进程-接收和处理待发送的邮件',
+ 'cleanup': '系统进程-服务器释放资源进程',
+ 'trivial-rewrite': '系统进程-邮件重写和转发服务',
+ 'bt-ipfilter': '宝塔网络的IP过滤器',
+ 'oneav': '微步木马检测服务',
+ 'rhsmcertd': '系统进程-验证系统的订阅状态服务',
+ 'tamperuser': '宝塔-企业级防篡改服务',
+ 'lvmetad': '系统进程-元数据守护进程',
+ 'containerd-shim-runc-v2': 'docker容器管理服务',
+ 'tuned': '系统进程-优化系统服务',
+ 'chronyd': '系统进程-时间同步服务',
+ 'auditd': '系统进程-系统安全日志记录服务',
+ 'gssproxy': '系统进程-身份验证和授权服务',
+ 'ossfs': '阿里云对象存储挂载服务',
+ 'cosfs': '腾讯云对象存储挂载服务',
+ 'obsfs': '华为云对象存储挂载服务',
+ 's3fs': '对象存储挂载服务',
+ 'bosfs': '百度云对象存储挂载服务',
+ 'jsvc': 'tomcat服务',
+ 'oneavd': '微步木马检测服务',
+ 'btsync': '宝塔文件同步服务',
+ 'mysqld': 'MySQL服务',
+ 'php-fpm': 'PHP子进程',
+ 'php-cgi': 'PHP-CGI进程',
+ 'nginx': 'Nginx服务',
+ 'httpd': 'Apache服务',
+ 'sshd': 'SSH服务',
+ 'pure-ftpd': 'FTP服务',
+ 'sftp-server': 'SFTP服务',
+ 'mysqld_safe': 'MySQL服务',
+ 'firewalld': '防火墙服务',
+ 'BT-Panel': '宝塔面板-主进程',
+ 'BT-Task': '宝塔面板-后台任务进程',
+ 'NetworkManager': '网络管理服务',
+ 'svlogd': '日志守护进程',
+ 'memcached': 'Memcached缓存器',
+ 'gunicorn': "python项目",
+ "BTPanel": '宝塔面板',
+ 'baota_coll': "堡塔云控-主控端",
+ 'baota_client': "堡塔云控-被控端",
+ 'node': 'Node.js程序',
+ 'supervisord': 'Supervisor进程',
+ 'rsyslogd': 'rsyslog日志服务',
+ 'crond': '计划任务服务',
+ 'cron': '计划任务服务',
+ 'rsync': 'rsync文件同步进程',
+ 'ntpd': '网络时间同步服务',
+ 'rpc.mountd': 'NFS网络文件系统挂载服务',
+ 'sendmail': 'sendmail邮件服务',
+ 'postfix': 'postfix邮件服务',
+ 'npm': 'Node.js NPM管理器',
+ 'PM2': 'Node.js PM2进程管理器',
+ 'htop': 'htop进程监控软件',
+ 'btpython': '宝塔面板-独立Python环境进程',
+ 'btappmanagerd': '宝塔应用管理器插件',
+ 'dockerd': 'Docker容器管理器',
+ 'docker-proxy': 'Docker容器管理器',
+ 'docker-registry': 'Docker容器管理器',
+ 'docker-distribution': 'Docker容器管理器',
+ 'docker-network': 'Docker容器管理器',
+ 'docker-volume': 'Docker容器管理器',
+ 'docker-swarm': 'Docker容器管理器',
+ 'docker-systemd': 'Docker容器管理器',
+ 'docker-containerd': 'Docker容器管理器',
+ 'docker-containerd-shim': 'Docker容器管理器',
+ 'docker-runc': 'Docker容器管理器',
+ 'docker-init': 'Docker容器管理器',
+ 'docker-init-systemd': 'Docker容器管理器',
+ 'docker-init-upstart': 'Docker容器管理器',
+ 'docker-init-sysvinit': 'Docker容器管理器',
+ 'docker-init-openrc': 'Docker容器管理器',
+ 'docker-init-runit': 'Docker容器管理器',
+ 'docker-init-systemd-resolved': 'Docker容器管理器',
+ 'rpcbind': 'NFS网络文件系统服务',
+ 'dbus-daemon': 'D-Bus消息总线守护进程',
+ 'systemd-logind': '登录管理器',
+ 'systemd-journald': 'Systemd日志管理服务',
+ 'systemd-udevd': '系统设备管理服务',
+ 'systemd-timedated': '系统时间日期服务',
+ 'systemd-timesyncd': '系统时间同步服务',
+ 'systemd-resolved': '系统DNS解析服务',
+ 'systemd-hostnamed': '系统主机名服务',
+ 'systemd-networkd': '系统网络管理服务',
+ 'systemd-resolvconf': '系统DNS解析服务',
+ 'systemd-local-resolv': '系统DNS解析服务',
+ 'systemd-sysctl': '系统系统参数服务',
+ 'systemd-modules-load': '系统模块加载服务',
+ 'systemd-modules-restore': '系统模块恢复服务',
+ 'agetty': 'TTY登陆验证程序',
+ 'sendmail-mta': 'MTA邮件传送代理',
+ 'bash': 'bash命令行进程',
+ '(sd-pam)': '可插入认证模块',
+ 'polkitd': '授权管理服务',
+ 'mongod': 'MongoDB数据库服务',
+ 'mongodb': 'MongoDB数据库服务',
+ 'mongodb-mms-monitor': 'MongoDB数据库服务',
+ 'mongodb-mms-backup': 'MongoDB数据库服务',
+ 'mongodb-mms-restore': 'MongoDB数据库服务',
+ 'mongodb-mms-agent': 'MongoDB数据库服务',
+ 'mongodb-mms-analytics': 'MongoDB数据库服务',
+ 'mongodb-mms-tools': 'MongoDB数据库服务',
+ 'mongodb-mms-backup-agent': 'MongoDB数据库服务',
+ 'mongodb-mms-backup-tools': 'MongoDB数据库服务',
+ 'mongodb-mms-restore-agent': 'MongoDB数据库服务',
+ 'mongodb-mms-restore-tools': 'MongoDB数据库服务',
+ 'mongodb-mms-analytics-agent': 'MongoDB数据库服务',
+ 'mongodb-mms-analytics-tools': 'MongoDB数据库服务',
+ 'dhclient': 'DHCP协议客户端',
+ 'dhcpcd': 'DHCP协议客户端',
+ 'dhcpd': 'DHCP服务器',
+ 'isc-dhcp-server': 'DHCP服务器',
+ 'isc-dhcp-server6': 'DHCP服务器',
+ 'dhcp6c': 'DHCP服务器',
+ 'dhcpcd': 'DHCP服务器',
+ 'dhcpd': 'DHCP服务器',
+ 'avahi-daemon': 'Zeroconf守护进程',
+ 'login': '登录进程',
+ 'systemd': '系统管理服务',
+ 'systemd-sysv': '系统管理服务',
+ 'systemd-journal-gateway': '系统管理服务',
+ 'systemd-journal-remote': '系统管理服务',
+ 'systemd-journal-upload': '系统管理服务',
+ 'systemd-networkd': '系统网络管理服务',
+ 'rpc.idmapd': 'NFS网络文件系统相关服务',
+ 'cupsd': '打印服务',
+ 'cups-browsed': '打印服务',
+ 'sh': 'shell进程',
+ 'php': 'PHP CLI模式进程',
+ 'blkmapd': 'NFS映射服务',
+ 'lsyncd': '文件同步服务',
+ 'sleep': '延迟进程'
+ }
+ if p_exe:
+ if name == 'php-fpm':
+ try:
+ php_version = '.'.join(p_exe.split('/')[-3])
+ return 'PHP' + php_version + '进程'
+ except:
+ pass
+ elif name == 'python':
+ p_exe_arr = p_exe.split('/')
+ if p_exe_arr[-1] in ['BT-Task', 'task.py']:
+ return '面板-后台任务进程'
+ elif p_exe_arr[-1] in ['BT-Panel', 'runserver.py']:
+ return '面板-主进程'
+ elif p_exe.find('process_network_total') != -1:
+ return '面板-进程网络监控'
+ if p:
+ cmdline = ' '.join(p.cmdline()).strip()
+ cmdline_arr = cmdline.split('/')
+ if cmdline.find('process_network_total') != -1:
+ return '进程网络监控'
+ if cmdline_arr[-1] in ['BT-Task', 'task.py']:
+ return '后台任务进程'
+ elif cmdline_arr[-1] in ['BT-Panel', 'runserver.py']:
+ return '主进程'
+ elif cmdline.find('process_network_total') != -1:
+ return '进程网络监控'
+ elif cmdline.find('tamper_proof_service') != -1:
+ return '网站防篡改'
+ elif cmdline.find('syssafe') != -1:
+ return '系统加固'
+ elif cmdline.find('opwaf') != -1:
+ return 'WAF防火墙'
+ elif cmdline.find('acme') != -1:
+ return 'SSL证书签发'
+ elif cmdline.find('psync') != -1:
+ return '面板一键迁移'
+ elif cmdline.find('/panel/plugin') != -1:
+ return '面板插件进程'
+ elif cmdline.find('/www/server/cron/') != -1:
+ return '面板计划任务'
+ elif name == 'nginx':
+ if p.username() == 'www':
+ return 'Nginx子进程'
+ else:
+ return 'Nginx主进程'
+ elif p_exe == '/usr/bin/bash':
+ cmdline = ' '.join(p.cmdline()).strip()
+ if cmdline.find('/www/server/cron/') != -1:
+ return '面板计划任务'
+ elif cmdline.find('/www/server/mdserver-web/plugins') != -1:
+ return '面板插件进程'
+
+ if name in processPs: return processPs[name]
+ if name == 'python':
+ if self.is_panel_process(pid): return 'MW面板'
+
+ if p_exe:
+ exe_keys = {
+ '/www/server/mdserver-web/plugins/': '面板插件',
+ '/www/server/cron/': '计划任务进程',
+ 'pm2': 'PM2进程管理器',
+ 'PM2': 'PM2进程管理器',
+ 'nvm': 'NVM Node版本管理器',
+ 'npm': 'NPM Node包管理器'
+ }
+
+ for k in exe_keys.keys():
+ if p_exe.find(k) != -1: return exe_keys[k]
+ if name.find(k) != -1: return exe_keys[k]
+
+ return name
+
+ def get_process_network(self, pid):
+ '''
+ @name 获取进程网络流量
+ @author hwliang<2021-09-13>
+ @param pid 进程ID
+ @return tuple
+ '''
+ if not self.__process_net_list:
+ self.get_process_net_list()
+ if not self.last_net_process_time: return 0, 0, 0, 0
+ if not pid in self.__process_net_list: return 0, 0, 0, 0
+
+ if not pid in self.last_net_process:
+ return self.__process_net_list[pid]['up'], self.__process_net_list[pid]['up_package'], \
+ self.__process_net_list[pid]['down'], self.__process_net_list[pid]['down_package']
+
+ up = int((self.__process_net_list[pid]['up'] - self.last_net_process[pid]['up']) / (
+ time.time() - self.last_net_process_time))
+ down = int((self.__process_net_list[pid]['down'] - self.last_net_process[pid]['down']) / (
+ time.time() - self.last_net_process_time))
+ up_package = int((self.__process_net_list[pid]['up_package'] - self.last_net_process[pid]['up_package']) / (
+ time.time() - self.last_net_process_time))
+ down_package = int(
+ (self.__process_net_list[pid]['down_package'] - self.last_net_process[pid]['down_package']) / (
+ time.time() - self.last_net_process_time))
+ return up, up_package, down, down_package
+
+ def get_process_cpu_time(self, cpu_times):
+ cpu_time = 0.00
+ for s in cpu_times: cpu_time += s
+ return cpu_time
+
+ # 获取cpu使用率
+ def get_cpu_percent(self, pid, cpu_times, cpu_time):
+ percent = 0.00
+ process_cpu_time = self.get_process_cpu_time(cpu_times)
+
+ if not self.old_info: self.old_info = {}
+ if not pid in self.old_info:
+ self.old_info[pid] = {}
+ self.old_info[pid]['cpu_time'] = process_cpu_time
+ return percent
+
+ if cpu_time == self.old_info['cpu_time']:
+ return 0.00
+
+ percent = round(100.00 * (process_cpu_time - self.old_info[pid]['cpu_time']) / (cpu_time - self.old_info['cpu_time']), 2)
+ # self.old_info[pid]['cpu_time'] = process_cpu_time
+
+ if percent > 0: return percent
+ return 0.00
+
+ # 获取平均负载
+ def get_load_average(self):
+ c = os.getloadavg()
+ data = {}
+ data['1'] = round(float(c[0]), 3) # float(c[0])
+ data['5'] = round(float(c[1]), 3) # float(c[1])
+ data['15'] = round(float(c[2]), 3) # float(c[2])
+ return data
+
+ def get_meter_head(self, get=None):
+ meter_head_file = getServerDir()+'/meter_head.json'
+ if os.path.exists(meter_head_file):
+ self.meter_head = json.loads(mw.readFile(meter_head_file))
+ else:
+ self.meter_head = {
+ 'name': True,
+ 'pid': True,
+ 'cpu_percent': True,
+ 'down': True,
+ 'up': True,
+ 'status': True,
+ 'threads': True,
+ 'user': True,
+ 'ps': True,
+ 'memory_used': True,
+ 'io_read_bytes': True,
+ 'io_write_bytes': True,
+ 'connects': True
+ }
+ mw.writeFile(meter_head_file, json.dumps(self.meter_head))
+ return self.meter_head
+
+ # 添加进程查找
+ def search_pro(self, data, search):
+ try:
+ ldata = []
+ for i in data:
+ if search in i['name'] or search in i['exe'] or search in i['ps'] or search in i[
+ 'user'] or search in str(i['pid']) or search in i['status']:
+ ldata.append(i)
+ elif hasattr(i, 'children'):
+ for k in i['children']:
+ if search in k['name'] or search in k['exe'] or search in k['ps'] or search in k[
+ 'user'] or search in str(k['pid']):
+ ldata.append(i)
+ return ldata
+ except:
+ print(mw.getTracebackInfo())
+ return data
+
+ def get_cpu_time(self):
+ cpu_times = psutil.cpu_times()
+
+ cpu_time = 0.00
+ for s in cpu_times: cpu_time += s
+ return cpu_time
+ # return s.user + s.system + s.nice + s.idle
+
+ # 获取python的路径
+ def get_python_bin(self):
+ mw_dir = mw.getServerDir() + '/mdserver-web'
+ bin_file = mw_dir + '/bin/python'
+ if os.path.exists(bin_file):
+ return bin_file
+ return '/usr/bin/python'
+
+ # 检查process_network_total.py是否运行
+ def check_process_net_total(self):
+ mw_dir = mw.getServerDir() + '/mdserver-web'
+ _pid_file = mw_dir+'/logs/process_network_total.pid'
+ if os.path.exists(_pid_file):
+ pid = public.readFile(_pid_file)
+ if os.path.exists('/proc/' + pid): return True
+
+ cmd_file = getServerDir()+'/process_network_total.py'
+ python_bin = self.get_python_bin()
+ _cmd = 'nohup {} {} 600 &> /tmp/net.log &'.format(python_bin, cmd_file)
+ mw.execShell(_cmd)
+
+ # 进程折叠,将子进程折叠到父进程下,并将使用资源累加。
+ def __pro_s_s(self, data: List) -> List:
+ """
+ 将子进程合并到父进程中
+ :param data:进程列表
+ :return:合并后的进程列表增加children字段
+ """
+ data1 = []
+ children_set = {'childrens': []}
+ for i in data:
+ if i['pid'] > 30 and i['ppid'] == 1:
+ children = self.__get_children(i['pid'])
+ s4 = time.time()
+ if children != []: children_set[i['pid']] = children
+ children_set['childrens'] += children
+ for i in data:
+ if i['pid'] in children_set:
+ i['children'] = []
+ for j in data:
+ if j['pid'] in children_set[i['pid']]:
+ i['children'].append(j)
+ i['memory_used'] += j['memory_used']
+ i['cpu_percent'] = round(i['cpu_percent'] + j['cpu_percent'], 2)
+ i['connects'] += j['connects']
+ i['threads'] += j['threads']
+
+ if 'io_write_bytes' in j:
+ i['io_write_bytes'] += j['io_write_bytes']
+ if 'io_read_bytes' in j:
+ i['io_read_bytes'] += j['io_read_bytes']
+ if 'io_write_speed' in j:
+ i['io_write_speed'] += j['io_write_speed']
+ if 'io_read_speed' in j:
+ i['io_read_speed'] += j['io_read_speed']
+
+ if 'up' in j:
+ i['up'] += j['up']
+ if 'up_package' in j:
+ i['up_package'] += j['up_package']
+
+ if 'down' in j:
+ i['down'] += j['down']
+ if 'down_package' in j:
+ i['down_package'] += j['down_package']
+ data1.append(i)
+ elif i['pid'] not in children_set['childrens']:
+ data1.append(i)
+ return data1
+
+ def __get_children(self, pid: int) -> List:
+ try:
+ p = psutil.Process(pid) # pid为指定进程的进程号
+ psutil.process_iter()
+ children = p.children(recursive=True) # 获取指定进程的所有子进程
+ pids = []
+ for child in children:
+ pids.append(child.pid)
+ return pids
+ except:
+ return []
+
+ def get_process_list(self, args = {}):
+ # https://hellowac.github.io/psutil-doc-zh/processes/process_class/oneshot.html
+ if self.is_mac:
+ return self.get_process_list_mac(args)
+ return self.get_process_list_linux(args)
+
+ def get_process_list_mac(self, args = {}):
+ self.new_info['cpu_time'] = self.get_cpu_time()
+ self.new_info['time'] = time.time()
+
+ sortx = 'all'
+ if 'sortx' in args: sortx = args['sortx']
+
+ if not 'sortx' in args:
+ args['sortx'] = 'status'
+ if args['sortx'] == 'status': res = False
+ if 'reverse' in args:
+ if args['reverse'] in ['undefined', 'null']:
+ args['reverse'] = 'True'
+ args['sortx'] = 'all'
+ if not args['reverse'] in ['True', 'False']: args['reverse'] = 'True'
+ res_list = {'True': True, 'False': False}
+ res = res_list[args['reverse']]
+ else:
+ args['reverse'] = True
+ if args['reverse'] in ['undefined', 'null']:
+ args['reverse'] = 'True'
+ args['sortx'] = 'all'
+
+ info = {}
+ info['activity'] = 0
+ info['cpu'] = 0.00
+ info['mem'] = 0
+ info['disk'] = 0
+ status_ps = {'sleeping': '睡眠', 'running': '活动'}
+ ppids = psutil.pids()
+ processList = []
+ for pid in ppids:
+ tmp = {}
+ try:
+ p = psutil.Process(pid)
+ with p.oneshot():
+ p_state = p.status()
+ try:
+ tmp['exe'] = p.exe()
+ except Exception as e:
+ continue
+
+ tmp['name'] = p.name()
+ tmp['pid'] = pid
+ tmp['ppid'] = p.ppid()
+ tmp['create_time'] = int(p.create_time())
+ tmp['status'] = p_state
+ tmp['user'] = p.username()
+ tmp['connects'] = self.get_connects(pid)
+
+ if p_state == 'running': info['activity'] += 1
+ if p_state in status_ps: p_state = status_ps[p_state]
+
+ try:
+ tmp['threads'] = p.num_threads()
+ except Exception as e:
+ continue
+
+
+ tmp['ps'] = self.get_process_ps(tmp['name'], pid, tmp['exe'], p)
+ tmp['up'], tmp['up_package'], tmp['down'], tmp['down_package'] = self.get_process_network(pid)
+
+
+ try:
+ p_cpus = p.cpu_times()
+ except Exception as e:
+ continue
+
+ try:
+ p_mem = p.memory_info()
+ except Exception as e:
+ continue
+ if p_mem.rss == 0: continue
+
+ tmp['memory_used'] = p_mem.rss
+ tmp['cpu_percent'] = self.get_cpu_percent(str(pid), p_cpus, self.new_info['cpu_time'])
+ # print(tmp['cpu_percent'])
+ if tmp['cpu_percent'] > 100: tmp['cpu_percent'] = 0.1
+ info['cpu'] += tmp['cpu_percent']
+ info['disk'] += 0
+
+ processList.append(tmp)
+ del (p)
+ del (tmp)
+ except Exception as e:
+ print("err:", mw.getTracebackInfo())
+ continue
+
+
+ processList = self.__pro_s_s(processList)
+ res = True
+
+ if args['sortx'] not in ['all']:
+ processList = sorted(processList, key=lambda x: x[args['sortx']], reverse=res)
+ else:
+ processList = sorted(processList, key=lambda x: [x['cpu_percent'], x['connects'], x['threads'],
+ x['memory_used']], reverse=res)
+
+ info['load_average'] = self.get_load_average()
+ data = {}
+ data['is_mac'] = self.is_mac
+ data['process_list'] = processList
+ info['cpu'] = round(info['cpu'], 3)
+ info['mem'] = self.get_mem_info()
+ data['info'] = info
+ if hasattr(args, 'search'):
+ if args.search != '':
+ data['process_list'] = self.search_pro(data['process_list'], args.search)
+ self.get_meter_head()
+ data['meter_head'] = self.meter_head
+
+ data['meter_head']['io_read_bytes'] = False
+ data['meter_head']['io_write_bytes'] = False
+ data['meter_head']['down'] = False
+ data['meter_head']['up'] = False
+ return data
+
+ # 获取进程信息
+ def get_process_list_linux(self, get = {}):
+ self.check_process_net_total()
+ self.Pids = psutil.pids()
+ processList = []
+ if type(self.new_info) != dict: self.new_info = {}
+ self.new_info['cpu_time'] = self.get_cpu_time()
+ self.new_info['time'] = time.time()
+ self.get_process_net_list()
+ if not 'sortx' in get: get.sortx = 'all'
+ info = {}
+ info['activity'] = 0
+ info['cpu'] = 0.00
+ info['mem'] = 0
+ info['disk'] = 0
+ status_ps = {'sleeping': '睡眠', 'running': '活动'}
+ for pid in self.Pids:
+ tmp = {}
+ try:
+ p = psutil.Process(pid)
+ with p.oneshot():
+ p_mem = p.memory_full_info()
+ if p_mem.rss == 0: continue
+ pio = p.io_counters()
+ p_cpus = p.cpu_times()
+ p_state = p.status()
+ if p_state == 'running': info['activity'] += 1
+ if p_state in status_ps: p_state = status_ps[p_state]
+ tmp['exe'] = p.exe()
+ tmp['name'] = p.name()
+ tmp['pid'] = pid
+ tmp['ppid'] = p.ppid()
+ # tmp['create_time'] = int(p.create_time())
+ tmp['status'] = p_state
+ tmp['user'] = p.username()
+ tmp['memory_used'] = p_mem.uss
+ tmp['cpu_percent'] = self.get_cpu_percent(str(pid), p_cpus, self.new_info['cpu_time'])
+ if tmp['name'] == 'BT-Panel' and tmp['cpu_percent'] > 1:
+ tmp['cpu_percent'] = round(tmp['cpu_percent'] % 1, 2)
+ tmp['io_write_bytes'] = pio.write_bytes
+ tmp['io_read_bytes'] = pio.read_bytes
+ tmp['io_write_speed'] = self.get_io_write(str(pid), pio.write_bytes)
+ tmp['io_read_speed'] = self.get_io_read(str(pid), pio.read_bytes)
+ tmp['connects'] = self.get_connects(pid)
+ tmp['threads'] = p.num_threads()
+ tmp['ps'] = self.get_process_ps(tmp['name'], pid, tmp['exe'], p)
+ tmp['up'], tmp['up_package'], tmp['down'], tmp['down_package'] = self.get_process_network(pid)
+ if tmp['cpu_percent'] > 100: tmp['cpu_percent'] = 0.1
+ info['cpu'] += tmp['cpu_percent']
+ info['disk'] += tmp['io_write_speed'] + tmp['io_read_speed']
+ processList.append(tmp)
+ del (p)
+ del (tmp)
+ except:
+ continue
+
+ cache.set(self.old_path, self.new_info, 600)
+ processList = self.__pro_s_s(processList)
+ res = True
+ if get.sortx == 'status': res = False
+ if 'reverse' in get:
+ if get.reverse in ['undefined', 'null']:
+ get.reverse = 'True'
+ get.sortx = 'all'
+ if not get.reverse in ['True', 'False']: get.reverse = 'True'
+ res_list = {'True': True, 'False': False}
+ res = res_list[get.reverse]
+ else:
+ get.reverse = True
+ if get.reverse in ['undefined', 'null']:
+ get.reverse = 'True'
+ get.sortx = 'all'
+ if get.sortx not in ['all']:
+ processList = sorted(processList, key=lambda x: x[get.sortx], reverse=res)
+ else:
+ processList = sorted(processList, key=lambda x: [x['cpu_percent'], x['up'], x['down'], x['io_write_speed'],
+ x['io_read_speed'], x['connects'], x['threads'],
+ x['memory_used']], reverse=res)
+ info['load_average'] = self.get_load_average()
+ data = {}
+ data['process_list'] = processList
+ info['cpu'] = round(info['cpu'], 2)
+ info['mem'] = self.get_mem_info()
+ data['info'] = info
+ if 'search' in get:
+ if get['search'] != '':
+ data['process_list'] = self.search_pro(data['process_list'], get.search)
+ self.get_meter_head()
+ data['meter_head'] = self.meter_head
+ return data
+
+ def object_to_dict(self, obj):
+ result = {}
+ for name in dir(obj):
+ value = getattr(obj, name)
+ if not name.startswith('__') and not callable(value) and not name.startswith('_'): result[name] = value
+ return result
+
+ def list_to_dict(self, data):
+ result = []
+ for s in data:
+ result.append(self.object_to_dict(s))
+ return result
+
+ # 获取进程的详细信息
+ def get_process_info(self, args={}):
+ pid = int(args['pid'])
+ try:
+ p = psutil.Process(pid)
+ processInfo = {}
+
+ if self.is_mac:
+ p_mem = self.object_to_dict(p.memory_info())
+ else:
+ p_mem = self.object_to_dict(p.memory_full_info())
+ pio = p.io_counters()
+ processInfo['io_write_bytes'] = pio.write_bytes;
+ processInfo['io_read_bytes'] = pio.read_bytes;
+ # p_cpus= p.cpu_times()
+ processInfo['exe'] = p.exe()
+ processInfo['name'] = p.name();
+ processInfo['pid'] = pid;
+ processInfo['ppid'] = p.ppid()
+ processInfo['pname'] = 'sys'
+ if processInfo['ppid'] != 0: processInfo['pname'] = psutil.Process(processInfo['ppid']).name()
+ processInfo['comline'] = p.cmdline()
+ processInfo['create_time'] = int(p.create_time())
+ processInfo['open_files'] = self.list_to_dict(p.open_files())
+ processInfo['status'] = p.status();
+ processInfo['user'] = p.username();
+ processInfo['memory_full'] = p_mem
+
+ processInfo['connects'] = self.get_connects(pid)
+ processInfo['threads'] = p.num_threads()
+ processInfo['ps'] = self.get_process_ps(processInfo['name'], pid, processInfo['exe'], p)
+ except Exception as e:
+ # print(mw.getTracebackInfo())
+ return mw.returnData(False, '指定进程已关闭!')
+ return processInfo
+
+ # 获取用户组处理函数 get_user_list——>引用get_group_name
+ def get_group_name(self, gid):
+ for g in self.groupList:
+ if g['gid'] == gid: return g['group']
+ return ''
+
+ # 用户名注释:ps get_user_list——>引用get_user_ps
+ def get_user_ps(self, name, ps):
+ userPs = {'www': '宝塔面板', 'root': '超级管理员', 'mysql': '用于运行MySQL的用户',
+ 'mongo': '用于运行MongoDB的用户',
+ 'git': 'git用户', 'mail': 'mail', 'nginx': '第三方nginx用户', 'postfix': 'postfix邮局用户',
+ 'lp': '打印服务帐号',
+ 'daemon': '控制后台进程的系统帐号', 'nobody': '匿名帐户', 'bin': '管理大部分命令的帐号',
+ 'adm': '管理某些管理文件的帐号', 'smtp': 'smtp邮件'}
+ if name in userPs: return userPs[name]
+ if not ps: return name
+ return ps
+
+ # 获取服务器的组名和id,从/etc/group中读取。存储到self.groupList,get_user_list——>引用get_group_list
+ def get_group_list(self, get):
+ tmpList = mw.readFile('/etc/group').split("\n")
+ groupList = []
+ for gl in tmpList:
+ tmp = gl.split(':')
+ if len(tmp) < 3: continue
+ groupInfo = {}
+ groupInfo['group'] = tmp[0]
+ groupInfo['gid'] = tmp[2]
+ groupList.append(groupInfo)
+ return groupList;
+
+ # 外部接口,删除用户,不能删除系统运行环境用户
+ def remove_user(self, get):
+ if self.is_mac:
+ return mw.returnData(False, '无法操作!')
+ users = ['www', 'root', 'mysql', 'shutdown', 'postfix', 'smmsp', 'sshd', 'systemd-network', 'systemd-bus-proxy',
+ 'avahi-autoipd', 'mail', 'sync', 'lp', 'adm', 'bin', 'mailnull', 'ntp', 'daemon', 'sys'];
+
+ if 'user' in get:
+ return mw.returnData(False, '缺少参数!')
+
+ if get['user'] in users: return mw.returnData(False, '不能删除系统和环境关键用户!')
+
+ r = mw.execShell("userdel " + get['user'])
+ if r[1].find('process') != -1:
+ try:
+ pid = r[1].split()[-1]
+ p = psutil.Process(int(pid))
+ pname = p.name()
+ p.kill()
+ mw.execShell("pkill -9 " + pname)
+ r = mw.execShell("userdel " + get.user)
+ except:
+ pass
+ if r[1].find('userdel:') != -1: return mw.returnData(False, r[1]);
+ return mw.returnData(True, '删除成功!')
+
+ # 获取用户列表 从/etc/passwd文件中读取
+ def get_user_list(self, get={}):
+ tmpList = mw.readFile('/etc/passwd').strip().split("\n")
+ userList = []
+ self.groupList = self.get_group_list(get)
+ for ul in tmpList:
+ tmp = ul.split(':')
+ if len(tmp) < 6: continue
+ userInfo = {}
+ userInfo['username'] = tmp[0]
+ userInfo['uid'] = tmp[2]
+ userInfo['gid'] = tmp[3]
+ userInfo['group'] = self.get_group_name(tmp[3])
+ userInfo['ps'] = self.get_user_ps(tmp[0], tmp[4])
+ userInfo['home'] = tmp[5]
+ userInfo['login_shell'] = tmp[6]
+ userList.append(userInfo)
+
+ # print(userList)
+ if 'search' in get:
+ if get['search'] != '':
+ userList = self.search_user(userList, get['search'])
+ return userList
+
+
+ # 获取当前网络连接信息
+ def get_network_list(self, get = {}):
+ data = {}
+ data['is_mac'] = False
+ if self.is_mac:
+ data['is_mac'] = self.is_mac
+ return data
+
+
+ netstats = psutil.net_connections()
+
+ networkList = []
+ for netstat in netstats:
+ tmp = {}
+ if netstat.type == 1:
+ tmp['type'] = 'tcp'
+ else:
+ tmp['type'] = 'udp'
+ tmp['family'] = netstat.family
+ tmp['laddr'] = netstat.laddr
+ tmp['raddr'] = netstat.raddr
+ tmp['status'] = netstat.status
+ p = psutil.Process(netstat.pid)
+ tmp['process'] = p.name()
+ if tmp['process'] in ['BT-Panel', 'gunicorn', 'baota_coll', 'baota_client']: continue
+ tmp['pid'] = netstat.pid
+ networkList.append(tmp)
+ del (p)
+ del (tmp)
+ networkList = sorted(networkList, key=lambda x: x['status'], reverse=True)
+
+ data['list'] = networkList
+ data['state'] = self.get_network()
+ if hasattr(get, 'search'):
+ if get.search != '':
+ data['list'] = self.search_network(data['list'], get.search)
+ return data
+
+ # 获取当前运行级别 get_service_list ——> 引用get_my_runlevel
+ def get_my_runlevel(self):
+ try:
+ runlevel = mw.execShell('runlevel')[0].split()[1]
+ except:
+ runlevel_dict = {"multi-user.target": '3', 'rescue.target': '1', 'poweroff.target': '0',
+ 'graphical.target': '5', "reboot.target": '6'}
+ r_tmp = mw.execShell('systemctl get-default')[0].strip()
+ if r_tmp in runlevel_dict:
+ runlevel = runlevel_dict[r_tmp]
+ else:
+ runlevel = '3'
+ return runlevel
+
+ # 服务注释 get_service_list——>引用 get_run_ps
+ def get_run_ps(self, name):
+ runPs = {'netconsole': '网络控制台日志', 'network': '网络服务', 'jexec': 'JAVA', 'tomcat8': 'Apache Tomcat',
+ 'tomcat7': 'Apache Tomcat', 'mariadb': 'Mariadb',
+ 'tomcat9': 'Apache Tomcat', 'tomcat': 'Apache Tomcat', 'memcached': 'Memcached缓存器',
+ 'php-fpm-53': 'PHP-5.3', 'php-fpm-52': 'PHP-5.2',
+ 'php-fpm-54': 'PHP-5.4', 'php-fpm-55': 'PHP-5.5', 'php-fpm-56': 'PHP-5.6', 'php-fpm-70': 'PHP-7.0',
+ 'php-fpm-71': 'PHP-7.1',
+ 'php-fpm-72': 'PHP-7.2', 'rsync_inotify': 'rsync实时同步', 'pure-ftpd': 'FTP服务',
+ 'mongodb': 'MongoDB', 'nginx': 'Web服务器(Nginx)',
+ 'httpd': 'Web服务器(Apache)', 'mw': '面板', 'mysqld': 'MySQL数据库', 'rsynd': 'rsync主服务',
+ 'php-fpm': 'PHP服务', 'systemd': '系统核心服务',
+ '/etc/rc.local': '用户自定义启动脚本', '/etc/profile': '全局用户环境变量',
+ '/etc/inittab': '用于自定义系统运行级别', '/etc/rc.sysinit': '系统初始化时调用的脚本',
+ 'sshd': 'SSH服务', 'crond': '计划任务服务', 'udev-post': '设备管理系统', 'auditd': '审核守护进程',
+ 'rsyslog': 'rsyslog服务', 'sendmail': '邮件发送服务', 'blk-availability': 'lvm2相关',
+ 'local': '用户自定义启动脚本', 'netfs': '网络文件系统', 'lvm2-monitor': 'lvm2相关',
+ 'xensystem': 'xen云平台相关', 'iptables': 'iptables防火墙', 'ip6tables': 'iptables防火墙 for IPv6',
+ 'firewalld': 'firewall防火墙'}
+ if name in runPs: return runPs[name]
+ return name
+
+ # 清除注释
+ def clear_comments(self, body):
+ bodyTmp = body.split("\n")
+ bodyR = ""
+ for tmp in bodyTmp:
+ if tmp.startswith('#'): continue
+ if tmp.strip() == '': continue
+ bodyR += tmp
+ return bodyR
+
+ # 获取启动项
+ def get_run_list(self, get={}):
+ data = {}
+ data['is_mac'] = False
+ if self.is_mac:
+ data['is_mac'] = self.is_mac
+ return data
+
+ runFile = ['/etc/rc.local', '/etc/profile', '/etc/inittab', '/etc/rc.sysinit']
+ runList = []
+ for rfile in runFile:
+ if not os.path.exists(rfile): continue
+ bodyR = self.clear_comments(mw.readFile(rfile))
+ if not bodyR: continue
+ stat = os.stat(rfile)
+ accept = str(oct(stat.st_mode)[-3:])
+ if accept == '644': continue
+ tmp = {}
+ tmp['name'] = rfile
+ tmp['srcfile'] = rfile
+ tmp['size'] = os.path.getsize(rfile)
+ tmp['access'] = accept
+ tmp['ps'] = self.get_run_ps(rfile)
+ # tmp['body'] = bodyR
+ runList.append(tmp)
+ runlevel = self.get_my_runlevel()
+ runPath = ['/etc/init.d', '/etc/rc' + runlevel + '.d']
+ tmpAll = []
+ islevel = False
+ for rpath in runPath:
+ if not os.path.exists(rpath): continue
+ if runPath[1] == rpath: islevel = True
+ for f in os.listdir(rpath):
+ if f[:1] != 'S': continue
+ filename = rpath + '/' + f
+ if not os.path.exists(filename): continue
+ if os.path.isdir(filename): continue
+ if os.path.islink(filename):
+ flink = os.readlink(filename).replace('../', '/etc/')
+ if not os.path.exists(flink): continue
+ filename = flink
+ tmp = {}
+ tmp['name'] = f
+ if islevel: tmp['name'] = f[3:]
+ if tmp['name'] in tmpAll: continue
+ stat = os.stat(filename)
+ accept = str(oct(stat.st_mode)[-3:])
+ if accept == '644': continue
+ tmp['srcfile'] = filename
+ tmp['access'] = accept
+ tmp['size'] = os.path.getsize(filename)
+ tmp['ps'] = self.get_run_ps(tmp['name'])
+ runList.append(tmp)
+ tmpAll.append(tmp['name'])
+ data = {}
+ data['run_list'] = runList
+ data['run_level'] = runlevel
+ if 'search' in get:
+ if get['search'] != '':
+ data['run_list'] = self.search_run(data['run_list'], get['search'])
+ return data
+
+ # 外部接口 查询服务启动级别 /etc/init.d/
+ def get_service_list(self, get = {}):
+ data = {}
+ data['is_mac'] = False
+ if self.is_mac:
+ data['is_mac'] = self.is_mac
+ return data
+
+ init_d = '/etc/init.d/'
+ serviceList = []
+ for sname in os.listdir(init_d):
+ try:
+ if str(oct(os.stat(init_d + sname).st_mode)[-3:]) == '644': continue
+ serviceInfo = {}
+ runlevels = self.get_runlevel(sname)
+ serviceInfo['name'] = sname
+ serviceInfo['runlevel_0'] = runlevels[0]
+ serviceInfo['runlevel_1'] = runlevels[1]
+ serviceInfo['runlevel_2'] = runlevels[2]
+ serviceInfo['runlevel_3'] = runlevels[3]
+ serviceInfo['runlevel_4'] = runlevels[4]
+ serviceInfo['runlevel_5'] = runlevels[5]
+ serviceInfo['runlevel_6'] = runlevels[6]
+ serviceInfo['ps'] = self.get_run_ps(sname)
+ serviceList.append(serviceInfo)
+ except:
+ continue
+
+ data['runlevel'] = self.get_my_runlevel()
+ data['serviceList'] = sorted(serviceList, key=lambda x: x['name'], reverse=False)
+ data['serviceList'] = self.get_systemctl_list(data['serviceList'], data['runlevel'])
+ if hasattr(get, 'search'):
+ if get.search != '':
+ data['serviceList'] = self.search_service(data['serviceList'], get.search)
+ return data
+
+ # 获取存放计划任务的路径
+ def get_cron_file(self):
+ filename = '/var/spool/cron/crontabs/root'
+ if os.path.exists(filename): return filename
+ filename = '/var/spool/cron/root'
+ if not os.path.exists(filename):
+ mw.writeFile(filename, "")
+ return filename
+
+ # 外部接口,获取计划任务列表
+ def get_cron_list(self, get = {}):
+ filename = self.get_cron_file()
+ tmpList = public.readFile(filename).split("\n")
+ cronList = []
+ for c in tmpList:
+ c = c.strip()
+ if c.startswith('#'): continue
+ tmp = c.split(' ')
+ if len(tmp) < 6: continue
+ cronInfo = {}
+ cronInfo['cycle'] = self.decode_cron_cycle(tmp)
+ if not cronInfo['cycle']: continue
+ ctmp = self.decode_cron_connand(tmp)
+ cronInfo['command'] = c
+ cronInfo['ps'] = ctmp[1]
+ cronInfo['exe'] = ctmp[2]
+ cronInfo['test'] = ctmp[0]
+ cronList.append(cronInfo)
+ if hasattr(get, 'search'):
+ if get.search != '':
+ cronList = self.search_cron(cronList, get.search)
+ return cronList
+
+ # 获取当前会话
+ def get_who(self, get = {}):
+ whoTmp = mw.execShell('who')[0]
+ tmpList = whoTmp.split("\n")
+ whoList = []
+ for w in tmpList:
+ tmp = w.split()
+ if len(tmp) < 5: continue
+ whoInfo = {}
+ whoInfo['user'] = tmp[0]
+ whoInfo['pts'] = tmp[1]
+ whoInfo['date'] = tmp[2] + ' ' + tmp[3]
+ whoInfo['ip'] = tmp[4].replace('(', '').replace(')', '')
+ if len(tmp) > 5:
+ whoInfo['date'] = tmp[2] + ' ' + tmp[3] + ' ' + tmp[4]
+ whoInfo['ip'] = tmp[5].replace('(', '').replace(')', '')
+ whoList.append(whoInfo)
+ if hasattr(get, 'search'):
+ if get.search != '':
+ whoList = self.search_who(whoList, get.search)
+ return whoList
+
+ def test_cpu(self):
+ pid = 43046
+ p = psutil.Process(pid)
+ tmp = {}
+ self.new_info['cpu_time'] = self.get_cpu_time()
+ self.new_info['time'] = time.time()
+ with p.oneshot():
+ p_cpus = p.cpu_times()
+ print(p_cpus)
+
+ tmp['cpu_percent'] = self.get_cpu_percent(str(pid), p_cpus, self.new_info['cpu_time'])
+ print(tmp['cpu_percent'])
+
+
+mc_instance = mainClass.instance()
+
+def get_network_list(args = {}):
+ return mc_instance.get_network_list(args)
+
+def get_process_list(args = {}):
+ return mc_instance.get_process_list(args)
+
+def get_service_list(args = {}):
+ return mc_instance.get_service_list(args)
+
+def get_run_list(args = {}):
+ return mc_instance.get_run_list(args)
+
+def get_cron_list(args = {}):
+ return mc_instance.get_cron_list(args)
+
+def get_who(args = {}):
+ return mc_instance.get_who(args)
+
+def get_process_info(args = {}):
+ return mc_instance.get_process_info(args)
+
+def get_user_list(args = {}):
+ return mc_instance.get_user_list(args)
+
+def remove_user(args = {}):
+ return mc_instance.remove_user(args)
+
+if __name__ == "__main__":
+ # mc_instance.get_process_list()
+ print(mc_instance.get_process_info({'pid':66647}))
+ # for x in range(10):
+ # mc_instance.test_cpu()
+ # time.sleep(1)
+
+ # mc_instance.test_cpu()
+ # time.sleep(1)
+ # mc_instance.test_cpu()