mirror of https://github.com/midoks/mdserver-web
parent
19a4974537
commit
6c40e57ff6
After Width: | Height: | Size: 455 B |
@ -0,0 +1,554 @@ |
|||||||
|
<style> |
||||||
|
/*任务管理器*/ |
||||||
|
.man-menu-sub { |
||||||
|
background-color: #fff; |
||||||
|
border-bottom: 1px solid #ccc; |
||||||
|
height: 50px; |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
justify-content: space-between; |
||||||
|
flex-wrap: nowrap; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
.t-mana .table > tbody > tr.active td { |
||||||
|
background-color: #E4EEE0; |
||||||
|
} |
||||||
|
|
||||||
|
.search-bar { |
||||||
|
} |
||||||
|
|
||||||
|
.search-bar .search_input { |
||||||
|
height: 30px; |
||||||
|
line-height: 30px; |
||||||
|
border-radius: 2px; |
||||||
|
border: 1px solid #ccc; |
||||||
|
outline: none; |
||||||
|
padding-left: 8px; |
||||||
|
vertical-align: top; |
||||||
|
width: 230px; |
||||||
|
} |
||||||
|
|
||||||
|
.search-bar .search_input:focus { |
||||||
|
border-color: #20a53a; |
||||||
|
|
||||||
|
span.glyphicon-search { |
||||||
|
color: #20a53a; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.search-bar .glyphicon { |
||||||
|
position: relative; |
||||||
|
top: 1px; |
||||||
|
display: inline-block; |
||||||
|
font-family: 'Glyphicons Halflings'; |
||||||
|
font-style: normal; |
||||||
|
font-weight: 400; |
||||||
|
line-height: 1; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
} |
||||||
|
|
||||||
|
.search-bar .glyphicon-search { |
||||||
|
height: 28px; |
||||||
|
line-height: 28px; |
||||||
|
padding: 0 10px; |
||||||
|
color: #888; |
||||||
|
position: absolute; |
||||||
|
right: 14px; |
||||||
|
top: 11px; |
||||||
|
font-size: 14px; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
.r56 { |
||||||
|
right: 56px !important; |
||||||
|
} |
||||||
|
|
||||||
|
.man-menu-sub { |
||||||
|
background-color: #fff; |
||||||
|
border-bottom: 1px solid #ccc; |
||||||
|
height: 50px; |
||||||
|
} |
||||||
|
|
||||||
|
.man-menu-sub span { |
||||||
|
padding: 14px 15px; |
||||||
|
cursor: pointer; |
||||||
|
display: inline-block; |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
|
||||||
|
.man-menu-sub .on { |
||||||
|
border-bottom: 2px solid #20a53a; |
||||||
|
color: #20a53a; |
||||||
|
font-weight: bold; |
||||||
|
} |
||||||
|
|
||||||
|
.soft-ico-min { |
||||||
|
display: inline-block; |
||||||
|
width: 16px; |
||||||
|
margin-right: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
.soft-ico-min img { |
||||||
|
width: 16px; |
||||||
|
} |
||||||
|
|
||||||
|
.table-cont { |
||||||
|
height: 500px; |
||||||
|
overflow: auto; |
||||||
|
border: #ddd 1px solid; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.ts-line { |
||||||
|
position: absolute; |
||||||
|
top: 99px; |
||||||
|
height: 1px; |
||||||
|
background-color: #ddd; |
||||||
|
left: 16px; |
||||||
|
z-index: 2; |
||||||
|
} |
||||||
|
|
||||||
|
.t-mana .bt-ico-ask { |
||||||
|
height: 14px; |
||||||
|
width: 14px; |
||||||
|
line-height: 14px; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info { |
||||||
|
width: 100%; |
||||||
|
border-top: #DBDBEA 1px solid; |
||||||
|
background-color: #f6f6f6; |
||||||
|
padding: 15px; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info-box { |
||||||
|
width: 500px; |
||||||
|
margin: 0 auto; |
||||||
|
background-color: #fff; |
||||||
|
border: #DBDBEA 1px solid; |
||||||
|
border-radius: 6px; |
||||||
|
height: 66px; |
||||||
|
box-shadow: 0 0 40px #eee; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info-con { |
||||||
|
float: left; |
||||||
|
height: 100%; |
||||||
|
width: 33%; |
||||||
|
line-height: 26px; |
||||||
|
padding: 6px 16px; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info-con:nth-of-type(2) { |
||||||
|
border-left: #DBDBEA 1px solid; |
||||||
|
border-right: #DBDBEA 1px solid; |
||||||
|
width: 34%; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info-con p { |
||||||
|
text-align: right; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-info-con .tname { |
||||||
|
display: inline-block; |
||||||
|
position: absolute; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.mini-level { |
||||||
|
border: #ddd 1px solid; |
||||||
|
width: 166px; |
||||||
|
background-color: #fff; |
||||||
|
border-radius: 6px; |
||||||
|
margin: 0 auto; |
||||||
|
height: 66px; |
||||||
|
line-height: 66px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.jc-detail .tname { |
||||||
|
font-size: 12px; |
||||||
|
font-weight: bold; |
||||||
|
margin-right: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.jc-detail h3.tname { |
||||||
|
margin-bottom: 10px; |
||||||
|
margin-top: 15px; |
||||||
|
color: #999; |
||||||
|
} |
||||||
|
|
||||||
|
.jc-detail .jc-info { |
||||||
|
margin: 10px 0; |
||||||
|
border-bottom: #ddd 1px solid; |
||||||
|
padding-bottom: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement .td-pid { |
||||||
|
/* display: flex; */ |
||||||
|
/* border-top: #ddd 2px solid; */ |
||||||
|
/* height: 38px; */ |
||||||
|
/* height: 100%; */ |
||||||
|
/* margin-top: 1px; */ |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid img { |
||||||
|
/* margin-right: 8px; */ |
||||||
|
/* display: inline-block; */ |
||||||
|
float: left; |
||||||
|
cursor: pointer; |
||||||
|
/* position: relative; |
||||||
|
left: -80px; |
||||||
|
filter: drop-shadow(#fff 80px 0); */ |
||||||
|
/* position: relative; |
||||||
|
left: -80px; |
||||||
|
filter: drop-shadow(#238B37 0 80px); */ |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid svg { |
||||||
|
float: left; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid .colp { |
||||||
|
transform: rotate(-90deg); |
||||||
|
-moz-transform: rotate(-90deg); |
||||||
|
-webkit-transform: rotate(-90deg); |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid .arrow:hover { |
||||||
|
filter: drop-shadow(#999999 0 0) |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid .process-child { |
||||||
|
margin-left: 50px; |
||||||
|
/* display: none; */ |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid span { |
||||||
|
display: inline-block; |
||||||
|
float: right; |
||||||
|
} |
||||||
|
|
||||||
|
.td-pid a { |
||||||
|
display: block; |
||||||
|
margin-left: 30px; |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement th: { |
||||||
|
height: 34px; |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement tr: { |
||||||
|
height: 38px; |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement tr:hover { |
||||||
|
/* background-color: rgb(245, 247, 250,0.6); */ |
||||||
|
background-color: rgb(246, 246, 246, 0.65); |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement .process-select { |
||||||
|
/* background-color: rgb(242, 242, 242); */ |
||||||
|
/* background-color: rgb(245, 247, 250,0.6); */ |
||||||
|
background-color: rgb(246, 246, 246, 0.6); |
||||||
|
/* background-color: rgb(246, 246, 246,0.65); */ |
||||||
|
} |
||||||
|
|
||||||
|
#taskResourceTable .process-select { |
||||||
|
/* background-color: rgb(242, 242, 242); */ |
||||||
|
background-color: #F1F9F3; |
||||||
|
} |
||||||
|
|
||||||
|
#TaskManagement .process-select:hover { |
||||||
|
/* background-color: rgb(211, 210, 210); */ |
||||||
|
/* background-color: rgb(245, 247, 250); */ |
||||||
|
background-color: rgb(246, 246, 246); |
||||||
|
/* border: 1px solid #ddd; |
||||||
|
box-sizing: border-box; */ |
||||||
|
} |
||||||
|
|
||||||
|
#taskResourceTable .process-select:hover { |
||||||
|
/* background-color: rgb(211, 210, 210); */ |
||||||
|
background-color: #BCE4C4; |
||||||
|
} |
||||||
|
|
||||||
|
.resource-panel { |
||||||
|
display: none; |
||||||
|
width: 100%; |
||||||
|
height: 700px; |
||||||
|
/* height: 300px; */ |
||||||
|
} |
||||||
|
|
||||||
|
.resource-tab { |
||||||
|
float: left; |
||||||
|
width: 100px; |
||||||
|
height: 300px; |
||||||
|
background-color: thistle; |
||||||
|
} |
||||||
|
|
||||||
|
.resource-right { |
||||||
|
margin-left: 100px; |
||||||
|
/* width: 100%; */ |
||||||
|
/* background-color: gray; */ |
||||||
|
/* height: 600px; */ |
||||||
|
} |
||||||
|
|
||||||
|
.resource-panel-show { |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.divtable-hide { |
||||||
|
display: none; |
||||||
|
/* visibility: hidden; */ |
||||||
|
} |
||||||
|
|
||||||
|
.resource-tab span { |
||||||
|
display: block; |
||||||
|
height: 30px; |
||||||
|
line-height: 30px; |
||||||
|
text-align: center; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
|
||||||
|
.resource-tab span:hover { |
||||||
|
background-color: #ccc; |
||||||
|
} |
||||||
|
|
||||||
|
.plug_menu { |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.plug_menu .setting_ul::after{ |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.plug_menu .setting_ul.undisplay::after { |
||||||
|
content: ''; |
||||||
|
position: absolute; |
||||||
|
color: #fff; |
||||||
|
width: 12px; |
||||||
|
height: 12px; |
||||||
|
font-size: 14px; |
||||||
|
top: -7px; |
||||||
|
right: 8px; |
||||||
|
display: inline-block; |
||||||
|
background: #fff; |
||||||
|
transform: rotate(-45deg); |
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.25); |
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.25); |
||||||
|
} |
||||||
|
|
||||||
|
.set_list_fid_dropdown { |
||||||
|
display: inline-block; |
||||||
|
line-height: 30px; |
||||||
|
margin-left: 10px; |
||||||
|
position: relative; |
||||||
|
vertical-align: bottom; |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .setting_btn { |
||||||
|
border: 1px solid #ccc; |
||||||
|
height: 30px; |
||||||
|
width: 30px; |
||||||
|
border-radius: 4px; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .setting_btn:hover{ |
||||||
|
background: #e9f6eb; |
||||||
|
border-color: #bce4c4; |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .icon-setting { |
||||||
|
color: rgb(102, 102, 102); |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .setting_btn:hover .icon-setting { |
||||||
|
color: #20a53a; |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .setting_ul { |
||||||
|
position: absolute; |
||||||
|
z-index: 99; |
||||||
|
background: #fff; |
||||||
|
width: 150px; |
||||||
|
right: 0; |
||||||
|
border-radius: 4px; |
||||||
|
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25); |
||||||
|
padding: 10px 0; |
||||||
|
margin-top: 10px; |
||||||
|
display: none; |
||||||
|
} |
||||||
|
.set_list_fid_dropdown .setting_ul::after { |
||||||
|
content: ''; |
||||||
|
position: absolute; |
||||||
|
color: #fff; |
||||||
|
width: 12px; |
||||||
|
height: 12px; |
||||||
|
font-size: 14px; |
||||||
|
top: -7px; |
||||||
|
right: 8px; |
||||||
|
display: inline-block; |
||||||
|
background: #fff; |
||||||
|
transform: rotate(-45deg); |
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.25); |
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.25); |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li{ |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
line-height: 27px; |
||||||
|
padding: 0 16px; |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li:hover{ |
||||||
|
background: #e9f6eb; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.disabled { |
||||||
|
cursor: not-allowed; |
||||||
|
} |
||||||
|
|
||||||
|
.setting_ul .setting_ul_li i { |
||||||
|
display: inline-block; |
||||||
|
width: 16px; |
||||||
|
height: 16px; |
||||||
|
border: 1px solid #ccc; |
||||||
|
background-color: #fff; |
||||||
|
vertical-align: top; |
||||||
|
position: relative; |
||||||
|
border-radius: 2px; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.active i { |
||||||
|
background-color: #20a53a; |
||||||
|
border-color: #20a53a; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.disabled i { |
||||||
|
background-color: #edf2fc; |
||||||
|
border-color: #dcdfe6; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.active.disabled i { |
||||||
|
background-color: #f2f6fc; |
||||||
|
border-color: #dcdfe6; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.active.disabled i::after{ |
||||||
|
border: solid #dcdfe6; |
||||||
|
border-width: 0 2px 2px 0; |
||||||
|
} |
||||||
|
.setting_ul .setting_ul_li.active i::after{ |
||||||
|
content: ''; |
||||||
|
position: absolute; |
||||||
|
display: block; |
||||||
|
left: 50%; |
||||||
|
top: 50%; |
||||||
|
margin-left: -2px; |
||||||
|
margin-top: -6px; |
||||||
|
width: 5px; |
||||||
|
height: 10px; |
||||||
|
border: solid #fff; |
||||||
|
border-width: 0 2px 2px 0; |
||||||
|
transform: rotate(45deg); |
||||||
|
} |
||||||
|
</style> |
||||||
|
|
||||||
|
<div class="t-mana TaskManView"> |
||||||
|
<div class="man-menu-sub mlr15"> |
||||||
|
<div> |
||||||
|
<span class="p_list on">进程</span> |
||||||
|
<!-- <span class="p_resource">资源</span> --> |
||||||
|
<span class="p_run">启动项</span> |
||||||
|
<span class="p_service">服务</span> |
||||||
|
<span class="p_network">网络</span> |
||||||
|
<span class="p_user">用户</span> |
||||||
|
<span class="p_cron">计划任务</span> |
||||||
|
<span class="p_session">会话</span> |
||||||
|
</div> |
||||||
|
<div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;"> |
||||||
|
<div class="search-bar "> |
||||||
|
<input type="text" class="search_input " style="" placeholder="支持名称、字段模糊搜索"> |
||||||
|
<span class="glyphicon glyphicon-search r56" aria-hidden="true"></span> |
||||||
|
</div> |
||||||
|
<div class="table_config set_list_fid_dropdown" title="设置表头"> |
||||||
|
<div class="setting_btn"><i class="glyphicon glyphicon-cog icon-setting"></i></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="ts-line"></div> |
||||||
|
|
||||||
|
<div class="divtable taskdivtable pd15"> |
||||||
|
<div id="table-cont" class="table-cont"> |
||||||
|
<table id="TaskManagement" class="table table-hover" width="100%" style="border:none"></table> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="resource-panel pd15"> |
||||||
|
<div class="resource-tab"> |
||||||
|
<span>CPU</span> |
||||||
|
<span>内存</span> |
||||||
|
<span>磁盘</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="resource-right"> |
||||||
|
<div class="resource-top"></div> |
||||||
|
<div class="resource-middle divtable"> |
||||||
|
<div id="table-cont" class="table-cont" style="height:100px;"> |
||||||
|
<table id="taskResourceTable" class="table table-hover" width="100%" style="border:none"> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="resource-bottom"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="mini-info" id="load_average"></div> |
||||||
|
<div class="plug_menu set_list_fid_dropdown"> |
||||||
|
<ul class="setting_ul" style="display: none;"> |
||||||
|
<li class="setting_ul_li ps active disabled" name="ps"> |
||||||
|
<i></i><span class="ml10">应用名称</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li pid active disabled" name="pid"> |
||||||
|
<i></i> <span class="ml10">PID</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li threads active" name="threads"> |
||||||
|
<i></i> <span class="ml10">线程</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li user active" name="user"> |
||||||
|
<i></i> <span class="ml10">用户</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li cpu_percent active disabled" name="cpu_percent"> |
||||||
|
<i></i> <span class="ml10">CPU</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li memory_used active disabled" name="memory_used"> |
||||||
|
<i></i> <span class="ml10">内存</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li io_read_bytes active" name="io_read_bytes"> |
||||||
|
<i></i> <span class="ml10">io读</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li io_write_bytes active" name="io_write_bytes"> |
||||||
|
<i></i> <span class="ml10">io写</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li up active" name="up"> |
||||||
|
<i></i> <span class="ml10">上行</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li down active" name="down"> |
||||||
|
<i></i> <span class="ml10">下行</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li connects active" name="connects"> |
||||||
|
<i></i> <span class="ml10">连接</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li status active" name="status"> |
||||||
|
<i></i> <span class="ml10">状态</span> |
||||||
|
</li> |
||||||
|
<li class="setting_ul_li active disabled" name=""> |
||||||
|
<i></i> <span class="ml10">操作</span> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript"> |
||||||
|
$('.layui-layer-page').css({'width': '1000px'}); |
||||||
|
$.getScript( "/plugins/file?name=task_manager&f=js/task_manager.js", function(){ |
||||||
|
console.log("load js ok!"); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
@ -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') |
@ -0,0 +1,17 @@ |
|||||||
|
{ |
||||||
|
"sort": 7, |
||||||
|
"ps": "轻松管理进程、流量监控、启动项、用户、服务、计划任务、会话[<span style='color:red;'>开发中</span>]", |
||||||
|
"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" |
||||||
|
} |
@ -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 |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,318 @@ |
|||||||
|
#coding: utf-8 |
||||||
|
#------------------------------------------------------------------- |
||||||
|
# 宝塔Linux面板 |
||||||
|
#------------------------------------------------------------------- |
||||||
|
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved. |
||||||
|
#------------------------------------------------------------------- |
||||||
|
# Author: hwliang<hwl@bt.cn> |
||||||
|
#------------------------------------------------------------------- |
||||||
|
|
||||||
|
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<int> 结束时间(秒),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<bytes> 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<bytes> 目标地址 |
||||||
|
@param src<bytes> 源地址 |
||||||
|
@param pack_size<int> 数据包长度 |
||||||
|
@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<string> 16进制的IP地址:16进程端口 |
||||||
|
@return tuple(ip<str>,port<int>) 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<bool> 是否强制刷新 |
||||||
|
@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<int> 端口 |
||||||
|
@return bytes |
||||||
|
''' |
||||||
|
return struct.pack('H',int(port))[::-1] |
||||||
|
|
||||||
|
def get_ip_pack(self,ip): |
||||||
|
''' |
||||||
|
@name 将IP地址转换为字节流 |
||||||
|
@author hwliang<2021-09-13> |
||||||
|
@param ip<str> 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<string> inode |
||||||
|
@param force<bool> 是否强制刷新 |
||||||
|
@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<bool> 是否强制刷新 |
||||||
|
@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<str> 进程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) |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue