正在显示
14 个修改的文件
包含
1030 行增加
和
1 行删除
app/modules/monitor/__init__.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +# author: 4N | |
3 | +#createtime: 2021/5/18 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | + | |
7 | +from flasgger import swag_from | |
8 | +from flask import Blueprint | |
9 | +from app.util import BlueprintApi | |
10 | +from . import monitor_info, monitoring, metrics, monitor_host_create, monitor_host_list, monitor_host_delete, monitor_host_edit | |
11 | + | |
12 | + | |
13 | +user_socket_list = [] | |
14 | +user_socket_dict = {} | |
15 | + | |
16 | + | |
17 | +class Monitor(BlueprintApi): | |
18 | + | |
19 | + bp = Blueprint("Monitor", __name__, url_prefix="/API/Monitor") | |
20 | + | |
21 | + @staticmethod | |
22 | + @bp.route('/Info', methods=['GET']) | |
23 | + @swag_from(monitor_info.Api.api_doc) | |
24 | + def monitor_info(): | |
25 | + """ | |
26 | + 性能监控 | |
27 | + """ | |
28 | + return monitor_info.Api().result | |
29 | + | |
30 | + @staticmethod | |
31 | + @bp.route('/baseMonitoring', methods=['GET']) | |
32 | + @swag_from(monitoring.Api.api_doc) | |
33 | + def monitoring(): | |
34 | + """ | |
35 | + 基础监控 | |
36 | + """ | |
37 | + return monitoring.Api().result | |
38 | + | |
39 | + @staticmethod | |
40 | + @bp.route('/metrics', methods=['GET']) | |
41 | + @swag_from(metrics.Api.api_doc) | |
42 | + def metrics(): | |
43 | + ''' | |
44 | + 指标统计 | |
45 | + ''' | |
46 | + return metrics.Api().result | |
47 | + | |
48 | + @staticmethod | |
49 | + @bp.route('/RegisterHost', methods=['POST']) | |
50 | + @swag_from(monitor_host_create.Api.api_doc) | |
51 | + def monitor_host_create(): | |
52 | + ''' | |
53 | + 注册监控主机 | |
54 | + ''' | |
55 | + return monitor_host_create.Api().result | |
56 | + | |
57 | + @staticmethod | |
58 | + @bp.route('/HostList', methods=['GET']) | |
59 | + @swag_from(monitor_host_list.Api.api_doc) | |
60 | + def monitor_host_list(): | |
61 | + ''' | |
62 | + 获取监控主机列表 | |
63 | + ''' | |
64 | + return monitor_host_list.Api().result | |
65 | + | |
66 | + @staticmethod | |
67 | + @bp.route('/HostDelete', methods=['POST']) | |
68 | + @swag_from(monitor_host_delete.Api.api_doc) | |
69 | + def monitor_host_delete(): | |
70 | + ''' | |
71 | + 删除主机 | |
72 | + ''' | |
73 | + return monitor_host_delete.Api().result | |
74 | + | |
75 | + @staticmethod | |
76 | + @bp.route('/HostEdit', methods=['POST']) | |
77 | + @swag_from(monitor_host_edit.Api.api_doc) | |
78 | + def monitor_host_edit(): | |
79 | + ''' | |
80 | + 编辑主机配置 | |
81 | + ''' | |
82 | + return monitor_host_edit.Api().result | ... | ... |
app/modules/monitor/metrics.py
0 → 100644
1 | +from datetime import datetime, timedelta | |
2 | + | |
3 | +from sqlalchemy.sql.functions import func | |
4 | +from .models import MonitorLog, db | |
5 | +from sqlalchemy import and_ | |
6 | +from app.util.component.ApiTemplate import ApiTemplate | |
7 | + | |
8 | + | |
9 | +class Api(ApiTemplate): | |
10 | + api_name = "统计指标" | |
11 | + | |
12 | + def process(self): | |
13 | + | |
14 | + # 返回结果 | |
15 | + res = {} | |
16 | + res["data"] = {} | |
17 | + logs = [] | |
18 | + try: | |
19 | + server = self.para.get("server") # server | |
20 | + # metrics_type = self.para.get("metrics_type") | |
21 | + grain = self.para.get("grain") | |
22 | + count = int(self.para.get("count")) | |
23 | + start_time = self.para.get("start") | |
24 | + to_time = self.para.get("to") | |
25 | + | |
26 | + cur_now = datetime.now() | |
27 | + start_datetime = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") | |
28 | + end_datetime = datetime.strptime(to_time, "%Y-%m-%d %H:%M:%S") | |
29 | + | |
30 | + if grain == "day": | |
31 | + # 粒度是一天 | |
32 | + format = "%Y-%m-%d" | |
33 | + logs = db.session.query(MonitorLog.date_stamp.label("key"), func.avg(MonitorLog.cpu_usage).label("cpu_usage"), | |
34 | + func.avg(MonitorLog.total_mem).label( | |
35 | + "total_mem"), | |
36 | + func.avg(MonitorLog.available_mem).label( | |
37 | + "available_mem"), | |
38 | + func.avg(MonitorLog.used_mem).label( | |
39 | + "used_mem"), | |
40 | + func.avg(MonitorLog.disk).label( | |
41 | + "disk"), | |
42 | + func.avg(MonitorLog.disk_usage).label( | |
43 | + "disk_usage"), | |
44 | + func.avg(MonitorLog.net_recv).label( | |
45 | + "net_recv"), | |
46 | + func.avg(MonitorLog.net_send).label("net_send")).filter(and_( | |
47 | + MonitorLog.date_stamp <= end_datetime.strftime( | |
48 | + format), | |
49 | + MonitorLog.date_stamp > start_datetime.strftime( | |
50 | + format), | |
51 | + MonitorLog.server == server)).group_by(MonitorLog.date_stamp).order_by(MonitorLog.date_stamp.asc()).all() | |
52 | + | |
53 | + keys = [] | |
54 | + keys_map = {} | |
55 | + while start_datetime <= end_datetime: | |
56 | + keys.append(self.get_monitor_log( | |
57 | + start_datetime.strftime('%Y-%m-%d'))) | |
58 | + keys_map[start_datetime.strftime('%Y-%m-%d')] = len(keys)-1 | |
59 | + start_datetime += timedelta(days=1) | |
60 | + | |
61 | + res["data"] = self.get_result(logs, keys, keys_map) | |
62 | + elif grain == "minu_five": | |
63 | + # 粒度是5分钟 | |
64 | + cur_minu = int(end_datetime.strftime("%M")) % 5 | |
65 | + logs = db.session.query(MonitorLog.hour_stamp.label("hour_stamp"), | |
66 | + MonitorLog.f_minu_stamp.label( | |
67 | + "minu_stamp"), | |
68 | + func.avg(MonitorLog.cpu_usage).label( | |
69 | + "cpu_usage"), | |
70 | + func.avg(MonitorLog.total_mem).label( | |
71 | + "total_mem"), | |
72 | + func.avg(MonitorLog.available_mem).label( | |
73 | + "available_mem"), | |
74 | + func.avg(MonitorLog.used_mem).label( | |
75 | + "used_mem"), | |
76 | + func.avg(MonitorLog.disk).label( | |
77 | + "disk"), | |
78 | + func.avg(MonitorLog.disk_usage).label( | |
79 | + "disk_usage"), | |
80 | + func.avg(MonitorLog.net_recv).label( | |
81 | + "net_recv"), | |
82 | + func.avg(MonitorLog.net_send).label("net_send")).filter(and_( | |
83 | + MonitorLog.time_stamp <= "{}:00".format( | |
84 | + end_datetime.strftime("%Y-%m-%d %H:%M")), | |
85 | + MonitorLog.time_stamp >= "{}:00".format( | |
86 | + start_datetime.strftime("%Y-%m-%d %H:%M")), | |
87 | + MonitorLog.server == server)).group_by(MonitorLog.date_stamp, MonitorLog.hour_stamp, MonitorLog.f_minu_stamp).order_by( | |
88 | + MonitorLog.hour_stamp.asc(), MonitorLog.f_minu_stamp.asc()).all() | |
89 | + | |
90 | + keys = [] | |
91 | + keys_map = {} | |
92 | + while start_datetime <= end_datetime: | |
93 | + key = start_datetime.strftime('%H:%M') | |
94 | + keys.append(self.get_monitor_log(key)) | |
95 | + keys_map[key] = len(keys)-1 | |
96 | + start_datetime += timedelta(minutes=5) | |
97 | + | |
98 | + logs = list(map(lambda log: | |
99 | + {"key": "%02d:%02d" % (log.hour_stamp, log.minu_stamp*5+cur_minu), | |
100 | + "cpu_usage": log.cpu_usage, "total_mem": log.total_mem, | |
101 | + "available_mem": log.available_mem, "used_mem": log.used_mem, "disk": log.disk, "disk_usage": log.disk_usage, | |
102 | + "net_recv": log.net_recv, "net_send": log.net_send}, | |
103 | + logs)) | |
104 | + | |
105 | + res["data"] = self.get_result_from_list(logs, keys, keys_map) | |
106 | + elif grain == "minu_ten": | |
107 | + # 粒度是10分钟 | |
108 | + cur_minu = int(end_datetime.strftime("%M")) % 10 | |
109 | + logs = db.session.query(MonitorLog.hour_stamp.label("hour_stamp"), | |
110 | + MonitorLog.d_minu_stamp.label( | |
111 | + "minu_stamp"), | |
112 | + func.avg(MonitorLog.cpu_usage).label( | |
113 | + "cpu_usage"), | |
114 | + func.avg(MonitorLog.total_mem).label( | |
115 | + "total_mem"), | |
116 | + func.avg(MonitorLog.available_mem).label( | |
117 | + "available_mem"), | |
118 | + func.avg(MonitorLog.used_mem).label( | |
119 | + "used_mem"), | |
120 | + func.avg(MonitorLog.disk).label( | |
121 | + "disk"), | |
122 | + func.avg(MonitorLog.disk_usage).label( | |
123 | + "disk_usage"), | |
124 | + func.avg(MonitorLog.net_recv).label( | |
125 | + "net_recv"), | |
126 | + func.avg(MonitorLog.net_send).label("net_send")).filter(and_( | |
127 | + MonitorLog.time_stamp <= "{}:00".format( | |
128 | + end_datetime.strftime("%Y-%m-%d %H:%M")), | |
129 | + MonitorLog.time_stamp >= "{}:00".format( | |
130 | + start_datetime.strftime("%Y-%m-%d %H:%M")), | |
131 | + MonitorLog.server == server)).group_by(MonitorLog.date_stamp, | |
132 | + MonitorLog.hour_stamp, | |
133 | + MonitorLog.d_minu_stamp).order_by(MonitorLog.hour_stamp.asc(), MonitorLog.d_minu_stamp.asc()).all() | |
134 | + keys = [] | |
135 | + keys_map = {} | |
136 | + while start_datetime <= end_datetime: | |
137 | + key = start_datetime.strftime('%H:%M') | |
138 | + keys.append(self.get_monitor_log(key)) | |
139 | + keys_map[key] = len(keys)-1 | |
140 | + start_datetime += timedelta(minutes=10) | |
141 | + | |
142 | + logs = list(map(lambda log: | |
143 | + {"key": "%02d:%02d" % (log.hour_stamp, log.minu_stamp*10+cur_minu), | |
144 | + "cpu_usage": log.cpu_usage, "total_mem": log.total_mem, | |
145 | + "available_mem": log.available_mem, "used_mem": log.used_mem, "disk": log.disk, "disk_usage": log.disk_usage, | |
146 | + "net_recv": log.net_recv, "net_send": log.net_send}, | |
147 | + logs)) | |
148 | + | |
149 | + res["data"] = self.get_result_from_list(logs, keys, keys_map) | |
150 | + elif grain == "hour": | |
151 | + # 粒度是一小时 | |
152 | + logs = db.session.query(MonitorLog.hour_stamp.label("key"), func.avg(MonitorLog.cpu_usage).label("cpu_usage"), | |
153 | + func.avg(MonitorLog.total_mem).label( | |
154 | + "total_mem"), | |
155 | + func.avg(MonitorLog.available_mem).label( | |
156 | + "available_mem"), | |
157 | + func.avg(MonitorLog.used_mem).label( | |
158 | + "used_mem"), | |
159 | + func.avg(MonitorLog.disk).label( | |
160 | + "disk"), | |
161 | + func.avg(MonitorLog.disk_usage).label( | |
162 | + "disk_usage"), | |
163 | + func.avg(MonitorLog.net_recv).label( | |
164 | + "net_recv"), | |
165 | + func.avg(MonitorLog.net_send).label("net_send")).filter(and_( | |
166 | + MonitorLog.time_stamp <= "{}:59:59".format( | |
167 | + end_datetime.strftime("%Y-%m-%d %H")), | |
168 | + MonitorLog.time_stamp >= "{}:59:59".format( | |
169 | + start_datetime.strftime("%Y-%m-%d %H")), | |
170 | + MonitorLog.server == server)).group_by(MonitorLog.hour_stamp).order_by(MonitorLog.hour_stamp.asc()).all() | |
171 | + keys = [] | |
172 | + keys_map = {} | |
173 | + while start_datetime <= end_datetime: | |
174 | + key = int(start_datetime.strftime('%H')) | |
175 | + keys.append(self.get_monitor_log("%02d时" % key)) | |
176 | + keys_map[str(key)] = len(keys)-1 | |
177 | + start_datetime += timedelta(hours=1) | |
178 | + | |
179 | + res["data"] = self.get_result(logs, keys, keys_map) | |
180 | + else: | |
181 | + # 按分钟统计 | |
182 | + logs = db.session.query(MonitorLog.hour_stamp.label("hour_stamp"), MonitorLog.minu_stamp.label("minu_stamp"), func.avg(MonitorLog.cpu_usage).label("cpu_usage"), | |
183 | + func.avg(MonitorLog.total_mem).label( | |
184 | + "total_mem"), | |
185 | + func.avg(MonitorLog.available_mem).label( | |
186 | + "available_mem"), | |
187 | + func.avg(MonitorLog.used_mem).label("used_mem"), | |
188 | + func.avg(MonitorLog.disk).label( | |
189 | + "disk"), | |
190 | + func.avg(MonitorLog.disk_usage).label( | |
191 | + "disk_usage"), | |
192 | + func.avg(MonitorLog.net_recv).label( | |
193 | + "net_recv"), | |
194 | + func.avg(MonitorLog.net_send).label("net_send")).filter(and_( | |
195 | + MonitorLog.time_stamp <= end_datetime.strftime("%Y-%m-%d %H:%M:%S"), | |
196 | + MonitorLog.time_stamp >= start_datetime.strftime("%Y-%m-%d %H:%M:%S"), | |
197 | + MonitorLog.server == server)).group_by(MonitorLog.hour_stamp, MonitorLog.minu_stamp).order_by( | |
198 | + MonitorLog.hour_stamp.asc(), MonitorLog.minu_stamp.asc()).all() | |
199 | + keys = [] | |
200 | + keys_map = {} | |
201 | + while start_datetime <= end_datetime: | |
202 | + key = start_datetime.strftime('%H:%M') | |
203 | + keys.append(self.get_monitor_log(key)) | |
204 | + keys_map[key] = len(keys)-1 | |
205 | + start_datetime += timedelta(minutes=1) | |
206 | + | |
207 | + logs = list(map(lambda log: | |
208 | + {"key": "%02d:%02d" % (log.hour_stamp, log.minu_stamp), | |
209 | + "cpu_usage": log.cpu_usage, "total_mem": log.total_mem, | |
210 | + "available_mem": log.available_mem, "used_mem": log.used_mem, "disk": log.disk, "disk_usage": log.disk_usage, | |
211 | + "net_recv": log.net_recv, "net_send": log.net_send}, | |
212 | + logs)) | |
213 | + | |
214 | + res["data"] = self.get_result_from_list(logs, keys, keys_map) | |
215 | + res["result"] = True | |
216 | + except Exception as e: | |
217 | + raise e | |
218 | + return res | |
219 | + | |
220 | + api_doc = { | |
221 | + "tags": ["监控接口"], | |
222 | + "parameters": [ | |
223 | + {"name": "server", | |
224 | + "in": "query", | |
225 | + "type": "string", | |
226 | + "description": "服务器地址"}, | |
227 | + {"name": "grain", | |
228 | + "in": "query", | |
229 | + "type": "string", | |
230 | + "description": "指标粒度:minu:分钟,minu_five:5分钟,minu_ten:10分钟,hour:1小时,day:每天"}, | |
231 | + {"name": "count", | |
232 | + "in": "query", | |
233 | + "type": "string", | |
234 | + "description": "个数"}, | |
235 | + {"name": "to", | |
236 | + "in": "query", | |
237 | + "type": "string", | |
238 | + "description": "查询终止时间"}, | |
239 | + {"name": "start", | |
240 | + "in": "query", | |
241 | + "type": "string", | |
242 | + "description": "查询起始时间"} | |
243 | + ], | |
244 | + "responses": { | |
245 | + 200: { | |
246 | + "schema": { | |
247 | + "properties": { | |
248 | + } | |
249 | + } | |
250 | + } | |
251 | + } | |
252 | + } | |
253 | + | |
254 | + def get_monitor_log(self, key): | |
255 | + return {"key": key, | |
256 | + "cpu_usage": None, "total_mem": None, | |
257 | + "available_mem": None, "used_mem": None, "disk": None, "disk_usage": None, | |
258 | + "net_recv": None, "net_send": None} | |
259 | + | |
260 | + def get_result(self, logs, keys, keys_map): | |
261 | + keys_map_key=keys_map.keys() | |
262 | + for log in logs: | |
263 | + if str(log.key) in keys_map_key: | |
264 | + tmp = keys[keys_map[str(log.key)]] | |
265 | + if tmp != None: | |
266 | + tmp['cpu_usage'] = log.cpu_usage | |
267 | + tmp['total_mem'] = log.total_mem | |
268 | + tmp['available_mem'] = log.available_mem | |
269 | + tmp['used_mem'] = log.used_mem | |
270 | + tmp['disk'] = log.disk | |
271 | + tmp['disk_usage'] = log.disk_usage | |
272 | + tmp['net_recv'] = log.net_recv | |
273 | + tmp['net_send'] = log.net_send | |
274 | + return keys | |
275 | + | |
276 | + def get_result_from_list(self, logs, keys, keys_map): | |
277 | + keys_map_key=keys_map.keys() | |
278 | + for log in logs: | |
279 | + if str(log["key"]) in keys_map_key: | |
280 | + tmp = keys[keys_map[str(log["key"])]] | |
281 | + if tmp != None: | |
282 | + tmp['cpu_usage'] = log["cpu_usage"] | |
283 | + tmp['total_mem'] = log["total_mem"] | |
284 | + tmp['available_mem'] = log["available_mem"] | |
285 | + tmp['used_mem'] = log["used_mem"] | |
286 | + tmp['disk'] = log["disk"] | |
287 | + tmp['disk_usage'] = log["disk_usage"] | |
288 | + tmp['net_recv'] = log["net_recv"] | |
289 | + tmp['net_send'] = log["net_send"] | |
290 | + return keys | ... | ... |
app/modules/monitor/models/__init__.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +# author: 4N | |
3 | +#createtime: 2021/6/11 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | + | |
7 | +from datetime import datetime | |
8 | +from time import time | |
9 | +from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, Time, Float, Binary | |
10 | +from sqlalchemy.orm import relationship | |
11 | +from sqlalchemy.sql.expression import column | |
12 | +from app.models import db | |
13 | + | |
14 | + | |
15 | +class MonitorLog(db.Model): | |
16 | + ''' | |
17 | + ''' | |
18 | + __tablename__ = "dmap_monitor_log" | |
19 | + guid = Column(String(256), primary_key=True) | |
20 | + server = Column(String(256)) | |
21 | + date_stamp = Column(Text) | |
22 | + hour_stamp = Column(Integer) | |
23 | + minu_stamp = Column(Integer) | |
24 | + d_minu_stamp = Column(Integer) # 10min粒度 1-6 | |
25 | + f_minu_stamp = Column(Integer) # 5min粒度 1~12 | |
26 | + time_stamp = Column(DateTime) # 创建时间戳 | |
27 | + cpu_usage = Column(Float) | |
28 | + total_mem = Column(Float) | |
29 | + available_mem = Column(Float) | |
30 | + used_mem = Column(Float) | |
31 | + disk = Column(Float) | |
32 | + disk_usage = Column(Float) | |
33 | + net_recv = Column(Float) | |
34 | + net_send = Column(Float) | |
35 | + | |
36 | + | |
37 | +class MonitorHost(db.Model): | |
38 | + ''' | |
39 | + 监控服务器配置 | |
40 | + ''' | |
41 | + __tablename__ = "dmap_monitor_host" | |
42 | + srcid = Column(String(256), primary_key=True) | |
43 | + host = Column(String(256)) | |
44 | + user = Column(String(256)) | |
45 | + password = Column(String(256)) | |
46 | + type = Column(String(256)) | |
47 | + host_name=Column(String(256)) | ... | ... |
app/modules/monitor/monitor_host_create.py
0 → 100644
1 | +from .models import MonitorHost, db | |
2 | +from sqlalchemy import and_ | |
3 | +from app.util.component.ApiTemplate import ApiTemplate | |
4 | +import uuid | |
5 | + | |
6 | + | |
7 | +class Api(ApiTemplate): | |
8 | + api_name = "注册主机" | |
9 | + | |
10 | + def para_check(self): | |
11 | + if not self.para.get("host"): | |
12 | + raise Exception("缺乏host参数") | |
13 | + if not self.para.get("user"): | |
14 | + raise Exception("缺乏user参数") | |
15 | + if not self.para.get("type"): | |
16 | + raise Exception("缺乏type参数") | |
17 | + if not self.para.get("passwd"): | |
18 | + raise Exception("缺乏passwd参数") | |
19 | + | |
20 | + def process(self): | |
21 | + | |
22 | + # 返回结果 | |
23 | + res = {} | |
24 | + res["data"] = {} | |
25 | + try: | |
26 | + host = self.para.get("host") # server | |
27 | + user = self.para.get("user") | |
28 | + password = self.para.get("passwd") | |
29 | + type = self.para.get("type") | |
30 | + host_name = self.para.get("host_name") | |
31 | + srcid = uuid.uuid1().__str__() | |
32 | + | |
33 | + if(db.session.query(MonitorHost.host).filter(MonitorHost.host == host).count() > 0): | |
34 | + res['message'] = '禁止重复注册host' | |
35 | + res["result"] = False | |
36 | + else: | |
37 | + monitorHost = MonitorHost( | |
38 | + srcid=srcid, host=host, user=user, password=password, type=type, host_name=host_name) | |
39 | + db.session.add(monitorHost) | |
40 | + db.session.commit() | |
41 | + res['data'] = {'host': host, 'srcid': srcid} | |
42 | + res["result"] = True | |
43 | + except Exception as e: | |
44 | + db.session.rollback() | |
45 | + raise e | |
46 | + return res | |
47 | + | |
48 | + api_doc = { | |
49 | + "tags": ["监控接口"], | |
50 | + "parameters": [ | |
51 | + {"name": "host", | |
52 | + "in": "formData", | |
53 | + "type": "string", | |
54 | + "description": "主机地址", | |
55 | + "required": "true"}, | |
56 | + {"name": "user", | |
57 | + "in": "formData", | |
58 | + "type": "string", | |
59 | + "description": "用户", | |
60 | + "required": "true"}, | |
61 | + {"name": "passwd", | |
62 | + "in": "formData", | |
63 | + "type": "string", | |
64 | + "description": "密码", | |
65 | + "required": "true"}, | |
66 | + {"name": "type", | |
67 | + "in": "formData", | |
68 | + "type": "string", | |
69 | + "description": "服务器类型", | |
70 | + "required": "true"}, | |
71 | + {"name": "host_name", | |
72 | + "in": "formData", | |
73 | + "type": "string", | |
74 | + "description": "主机名"} | |
75 | + ], | |
76 | + "responses": { | |
77 | + 200: { | |
78 | + "schema": { | |
79 | + "properties": { | |
80 | + } | |
81 | + } | |
82 | + } | |
83 | + } | |
84 | + } | ... | ... |
app/modules/monitor/monitor_host_delete.py
0 → 100644
1 | +from .models import MonitorHost, db | |
2 | +from sqlalchemy import and_ | |
3 | +from app.util.component.ApiTemplate import ApiTemplate | |
4 | +import uuid | |
5 | + | |
6 | + | |
7 | +class Api(ApiTemplate): | |
8 | + api_name = "注销主机" | |
9 | + | |
10 | + def para_check(self): | |
11 | + if not self.para.get("srcid"): | |
12 | + raise Exception("缺乏host参数") | |
13 | + | |
14 | + def process(self): | |
15 | + | |
16 | + # 返回结果 | |
17 | + res = {} | |
18 | + res["data"] = {} | |
19 | + try: | |
20 | + srcid = self.para.get("srcid") # server | |
21 | + monitor_host = MonitorHost.query.filter_by( | |
22 | + srcid=srcid).one_or_none() | |
23 | + if monitor_host: | |
24 | + db.session.delete(monitor_host) | |
25 | + db.session.commit() | |
26 | + res["result"] = True | |
27 | + res["message"] = "删除成功,srcid:{}".format(srcid) | |
28 | + else: | |
29 | + res['message'] = 'host不存在,无法注销' | |
30 | + res["result"] = False | |
31 | + except Exception as e: | |
32 | + db.session.rollback() | |
33 | + raise e | |
34 | + return res | |
35 | + | |
36 | + api_doc = { | |
37 | + "tags": ["监控接口"], | |
38 | + "parameters": [ | |
39 | + {"name": "srcid", | |
40 | + "in": "formData", | |
41 | + "type": "string", | |
42 | + "description": "srcid值", | |
43 | + "required": "true"} | |
44 | + ], | |
45 | + "responses": { | |
46 | + 200: { | |
47 | + "schema": { | |
48 | + "properties": { | |
49 | + } | |
50 | + } | |
51 | + } | |
52 | + } | |
53 | + } | ... | ... |
app/modules/monitor/monitor_host_edit.py
0 → 100644
1 | +from .models import MonitorHost, MonitorLog, db | |
2 | +from sqlalchemy import and_ | |
3 | +from app.util.component.ApiTemplate import ApiTemplate | |
4 | +import uuid | |
5 | + | |
6 | + | |
7 | +class Api(ApiTemplate): | |
8 | + api_name = "编辑主机配置" | |
9 | + | |
10 | + def para_check(self): | |
11 | + if not self.para.get("srcid"): | |
12 | + raise Exception("缺乏host参数") | |
13 | + | |
14 | + def process(self): | |
15 | + | |
16 | + # 返回结果 | |
17 | + res = {} | |
18 | + res["data"] = {} | |
19 | + try: | |
20 | + srcid = self.para.get("srcid") # server | |
21 | + passwd = self.para.get("passwd") | |
22 | + host_name = self.para.get("host_name") | |
23 | + # Catalog.query.filter_by(guid=self.para.get("guid")).update({"name":self.para.get("name")}) | |
24 | + | |
25 | + if passwd or host_name: | |
26 | + monitor_host = MonitorHost.query.filter_by(srcid=srcid) | |
27 | + if passwd: | |
28 | + monitor_host.update({"password": passwd}) | |
29 | + if host_name: | |
30 | + monitor_host.update({"host_name": host_name}) | |
31 | + db.session.commit() | |
32 | + | |
33 | + res["result"] = True | |
34 | + res["message"] = "更新成功".format(srcid) | |
35 | + | |
36 | + except Exception as e: | |
37 | + db.session.rollback() | |
38 | + raise e | |
39 | + return res | |
40 | + | |
41 | + api_doc = { | |
42 | + "tags": ["监控接口"], | |
43 | + "parameters": [ | |
44 | + {"name": "srcid", | |
45 | + "in": "formData", | |
46 | + "type": "string", | |
47 | + "description": "srcid值", | |
48 | + "required": "true"}, | |
49 | + {"name": "host_name", | |
50 | + "in": "formData", | |
51 | + "type": "string", | |
52 | + "description": "主机名"}, | |
53 | + {"name": "passwd", | |
54 | + "in": "formData", | |
55 | + "type": "string", | |
56 | + "description": "密码"} | |
57 | + ], | |
58 | + "responses": { | |
59 | + 200: { | |
60 | + "schema": { | |
61 | + "properties": { | |
62 | + } | |
63 | + } | |
64 | + } | |
65 | + } | |
66 | + } | ... | ... |
app/modules/monitor/monitor_host_list.py
0 → 100644
1 | +from sqlalchemy.sql.functions import func | |
2 | +from .models import MonitorHost, db | |
3 | +from sqlalchemy import and_ | |
4 | +from app.util.component.ApiTemplate import ApiTemplate | |
5 | + | |
6 | + | |
7 | +class Api(ApiTemplate): | |
8 | + api_name = "监控主机列表" | |
9 | + | |
10 | + def process(self): | |
11 | + | |
12 | + # 返回结果 | |
13 | + res = {} | |
14 | + res["data"] = [] | |
15 | + logs = [] | |
16 | + try: | |
17 | + datas = db.session.query( | |
18 | + MonitorHost.host.label("host"), MonitorHost.srcid.label( | |
19 | + "srcid"), MonitorHost.type.label("type"), | |
20 | + MonitorHost.host_name.label("host_name"), | |
21 | + MonitorHost.user.label("user")).all() | |
22 | + res["data"] = list(map(lambda data: | |
23 | + {'host': data.host, 'srcid': data.srcid, | |
24 | + 'type': data.type, 'host_name': data.host_name, | |
25 | + 'user': data.user}, | |
26 | + datas)) | |
27 | + res["result"] = True | |
28 | + except Exception as e: | |
29 | + raise e | |
30 | + return res | |
31 | + | |
32 | + api_doc = { | |
33 | + "tags": ["监控接口"], | |
34 | + "parameters": [ | |
35 | + ], | |
36 | + "responses": { | |
37 | + 200: { | |
38 | + "schema": { | |
39 | + "properties": { | |
40 | + } | |
41 | + } | |
42 | + } | |
43 | + } | |
44 | + } | ... | ... |
app/modules/monitor/monitor_info.py
0 → 100644
1 | +# coding=utf-8 | |
2 | +#author: 4N | |
3 | +#createtime: 2021/7/9 | |
4 | +#email: nheweijun@sina.com | |
5 | + | |
6 | +from app.models import * | |
7 | + | |
8 | +from app.util.component.ApiTemplate import ApiTemplate | |
9 | +from app.util.component.ModelVisitor import ModelVisitor | |
10 | +import psutil | |
11 | + | |
12 | +class Api(ApiTemplate): | |
13 | + api_name = "监控" | |
14 | + | |
15 | + def process(self): | |
16 | + | |
17 | + # 返回结果 | |
18 | + res = {} | |
19 | + res["data"] = {} | |
20 | + try: | |
21 | + # 业务逻辑 | |
22 | + cpu_count = psutil.cpu_count(False) | |
23 | + cpu_per = int(psutil.cpu_percent()) | |
24 | + res["data"]["cpu"] ={"count":cpu_count,"percent":"{}%".format(cpu_per)} | |
25 | + | |
26 | + | |
27 | + mem_total = int(psutil.virtual_memory()[0]) | |
28 | + mem_used = int(psutil.virtual_memory()[3]) | |
29 | + mem_per = int(psutil.virtual_memory()[2]) | |
30 | + | |
31 | + network_sent = int(psutil.net_io_counters()[0] / 8 ) # 每秒接受的kb | |
32 | + network_recv = int(psutil.net_io_counters()[1] / 8 ) | |
33 | + | |
34 | + res["data"]["memory"] = { | |
35 | + 'total': self.format_value(mem_total), | |
36 | + 'used': self.format_value(mem_used), | |
37 | + 'percent': "{}%".format(mem_per) | |
38 | + } | |
39 | + | |
40 | + | |
41 | + | |
42 | + | |
43 | + | |
44 | + res["data"]["network"] = { | |
45 | + 'sent': self.format_value(network_sent), | |
46 | + 'recv': self.format_value(network_recv) | |
47 | + } | |
48 | + | |
49 | + | |
50 | + res["result"] = True | |
51 | + except Exception as e: | |
52 | + raise e | |
53 | + return res | |
54 | + | |
55 | + api_doc = { | |
56 | + | |
57 | + "tags": ["监控接口"], | |
58 | + "parameters": [ | |
59 | + ], | |
60 | + "responses": { | |
61 | + 200: { | |
62 | + "schema": { | |
63 | + "properties": { | |
64 | + } | |
65 | + } | |
66 | + } | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + def format_value(self,value): | |
71 | + if value>1024**3: | |
72 | + value = "{}GB".format(format(value/1024.0**3,'.1f')) | |
73 | + elif value>1024**2: | |
74 | + value = "{}MB".format(format(value / 1024.0 ** 2, '.1f')) | |
75 | + elif value>1024: | |
76 | + value = "{}KB".format(format(value / 1024.0, '.1f')) | |
77 | + else: | |
78 | + value = "{}B".format(format(value, '.1f')) | |
79 | + return value | |
\ No newline at end of file | ... | ... |
app/modules/monitor/monitoring.py
0 → 100644
1 | +from app.models import * | |
2 | +from app.util.component.ApiTemplate import ApiTemplate | |
3 | +import json | |
4 | +import os | |
5 | + | |
6 | +class Api(ApiTemplate): | |
7 | + api_name = "远程监控" | |
8 | + | |
9 | + def process(self): | |
10 | + | |
11 | + # 返回结果 | |
12 | + res = {} | |
13 | + res["data"] = {} | |
14 | + try: | |
15 | + base_dir = os.getcwd() | |
16 | + | |
17 | + # 监控文件 | |
18 | + monitor_filepath = os.path.join(base_dir, 'file', 'monitor_log.txt') | |
19 | + monitor_file = open(monitor_filepath, "r") | |
20 | + log = monitor_file.read() | |
21 | + monitor_file.close() | |
22 | + res["data"]=json.loads(log) | |
23 | + res["result"] = True | |
24 | + except Exception as e: | |
25 | + raise e | |
26 | + return res | |
27 | + | |
28 | + api_doc = { | |
29 | + | |
30 | + "tags": ["监控接口"], | |
31 | + "parameters": [ | |
32 | + ], | |
33 | + "responses": { | |
34 | + 200: { | |
35 | + "schema": { | |
36 | + "properties": { | |
37 | + } | |
38 | + } | |
39 | + } | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + def format_value(self, value): | |
44 | + # 1024*1024*1024 | |
45 | + if value > 1_073_741_824: | |
46 | + value = "{}GB".format(format(value/1_073_741_824, '.1f')) | |
47 | + elif value > 1024**2: | |
48 | + value = "{}MB".format(format(value / 1_048_576, '.1f')) | |
49 | + elif value > 1024: | |
50 | + # 1024*1024 | |
51 | + value = "{}KB".format(format(value / 1024.0, '.1f')) | |
52 | + else: | |
53 | + value = "{}B".format(format(value, '.1f')) | |
54 | + return value | |
55 | + | |
56 | + | |
57 | + def Mb_format_value(self,value): | |
58 | + if value > 1024: | |
59 | + value = "{}GB".format(format(value/1024, '.1f')) | |
60 | + else: | |
61 | + value = "{}MB".format(format(value, '.1f')) | |
62 | + return value | ... | ... |
app/modules/monitor/schedule.py
0 → 100644
1 | +# import schedule | |
2 | +import os | |
3 | +import paramiko | |
4 | +from .models import MonitorHost, MonitorLog | |
5 | +import datetime | |
6 | +import math | |
7 | +import time | |
8 | +import uuid | |
9 | +import schedule | |
10 | +from app.util.component.RunContinuous import run_continuously | |
11 | +from app.util.component.PGUtil import PGUtil | |
12 | +import configure | |
13 | + | |
14 | + | |
15 | +def background_job(): | |
16 | + try: | |
17 | + # print('Hello from the background thread') | |
18 | + # base_dir = os.getcwd() | |
19 | + | |
20 | + # 命令文件 | |
21 | + # cmd_filepath = os.path.join(base_dir, "file", "monitor.txt") | |
22 | + # cmd_file = open(cmd_filepath, "r") | |
23 | + # cmd = cmd_file.read() | |
24 | + # cmd_file.close() | |
25 | + # servers = [{'sid': 'src1', 'hostname': '172.26.99.160', | |
26 | + # 'username': 'monitor', 'password': '123456'}, | |
27 | + # {'sid': 'src2', 'hostname': '172.26.60.100', | |
28 | + # 'username': 'root', 'password': 'DMap@123'}] | |
29 | + | |
30 | + cur_time = datetime.datetime.now() | |
31 | + time_stamp = cur_time.strftime( | |
32 | + "%Y-%m-%d %H:%M:%S") | |
33 | + struct_time = time.strptime(time_stamp, "%Y-%m-%d %H:%M:%S") | |
34 | + d_minu_stamp = math.floor(struct_time.tm_min/10) | |
35 | + f_minu_stamp = math.floor(struct_time.tm_min/5) | |
36 | + | |
37 | + sys_session = PGUtil.get_db_session( | |
38 | + configure.SQLALCHEMY_DATABASE_URI) | |
39 | + sys_ds = PGUtil.open_pg_data_source( | |
40 | + 0, configure.SQLALCHEMY_DATABASE_URI) | |
41 | + | |
42 | + hosts = sys_session.query( | |
43 | + MonitorHost.host, MonitorHost.user, MonitorHost.password, MonitorHost.type, MonitorHost.srcid) | |
44 | + servers = list(map(lambda host: | |
45 | + {'hostname': host.host, 'username': host.user, | |
46 | + 'password': host.password, 'type': host.type, | |
47 | + 'sid': host.srcid}, | |
48 | + hosts)) | |
49 | + for info in servers: | |
50 | + try: | |
51 | + # 业务逻辑 | |
52 | + client = paramiko.SSHClient() | |
53 | + client.set_missing_host_key_policy(paramiko.AutoAddPolicy) | |
54 | + client.connect(hostname=info['hostname'], | |
55 | + username=info['username'], password=info['password']) | |
56 | + | |
57 | + # cpu | |
58 | + order = "top -b -n1 | sed -n '3p' | awk '{print $2}'" | |
59 | + stdin, stdout, stderr = client.exec_command(order) | |
60 | + cpu_usage = stdout.read().decode().split("\n")[0] # cpu使用率 | |
61 | + | |
62 | + # 内存 | |
63 | + order = "free -m | sed -n '2p' | awk '{print $2}'" | |
64 | + stdin, stdout, stderr = client.exec_command(order) | |
65 | + totalMem = stdout.read().decode().split("\n")[0] # 总内存 | |
66 | + | |
67 | + order = "free -m | sed -n '2p' | awk '{print $7}'" | |
68 | + stdin, stdout, stderr = client.exec_command(order) | |
69 | + availableMem = stdout.read().decode().split("\n")[0] # 可用内存 | |
70 | + | |
71 | + order = "free -m | sed -n '2p' | awk '{print $3}'" | |
72 | + stdin, stdout, stderr = client.exec_command(order) | |
73 | + usedMem = stdout.read().decode().split("\n")[0] # 已用内存 | |
74 | + | |
75 | + # disk | |
76 | + order = "df -m | grep -v 'overlay\|Filesystem' | awk '{print $1,$2,$3}' | grep /dev | awk '{print $2}' | awk -v total=0 '{total+=$1}END{print total}'" | |
77 | + stdin, stdout, stderr = client.exec_command(order) | |
78 | + totalDisk = int(stdout.read().decode().split("\n") | |
79 | + [0]) # 总磁盘空间,单位Mb | |
80 | + | |
81 | + order = "df -m | grep -v 'overlay\|Filesystem' | awk '{print $1,$2,$3}' | grep /dev | awk '{print $3}' | awk -v total=0 '{total+=$1}END{print total}'" | |
82 | + stdin, stdout, stderr = client.exec_command(order) | |
83 | + usedDisk = int(stdout.read().decode().split("\n") | |
84 | + [0]) # 已使用磁盘空间,单位Mb | |
85 | + | |
86 | + # network | |
87 | + # 接收的字节数 | |
88 | + rx_time = [] | |
89 | + rx_bytes = [] | |
90 | + tx_time = [] | |
91 | + tx_bytes = [] | |
92 | + | |
93 | + # 接收的字节数 | |
94 | + order = "ifconfig | grep RX | grep -v 'errors'| awk -v total=0 '{total+=$5}END{print total}'" | |
95 | + i = 0 | |
96 | + while i < 2: | |
97 | + i = i+1 | |
98 | + stdin, stdout, stderr = client.exec_command(order) | |
99 | + rx_time.append(time.time()) | |
100 | + rx_bytes.append(int(stdout.read().decode().split("\n")[0])) | |
101 | + | |
102 | + # 发送的字节数 | |
103 | + order = "ifconfig | grep TX | grep -v 'errors'| awk -v total=0 '{total+=$5}END{print total}'" | |
104 | + i = 0 | |
105 | + while i < 2: | |
106 | + i = i+1 | |
107 | + stdin, stdout, stderr = client.exec_command(order) | |
108 | + tx_time.append(time.time()) | |
109 | + tx_bytes.append(int(stdout.read().decode().split("\n")[0])) | |
110 | + | |
111 | + log_guid = uuid.uuid1().__str__() | |
112 | + monitor_log = MonitorLog(guid=log_guid, | |
113 | + server=info["hostname"], | |
114 | + time_stamp=cur_time, | |
115 | + cpu_usage=float( | |
116 | + "%.2f" % float(cpu_usage)), | |
117 | + total_mem=totalMem, | |
118 | + available_mem=availableMem, | |
119 | + used_mem=usedMem, | |
120 | + disk=totalDisk, | |
121 | + disk_usage=usedDisk, | |
122 | + net_recv=float("%.2f" % float(( | |
123 | + rx_bytes[1] - rx_bytes[0])/(rx_time[1]-rx_time[0]))), | |
124 | + net_send=float("%.2f" % float(( | |
125 | + tx_bytes[1] - tx_bytes[0])/(tx_time[1]-tx_time[0]))), | |
126 | + date_stamp=cur_time.strftime( | |
127 | + "%Y-%m-%d"), | |
128 | + hour_stamp=struct_time.tm_hour, | |
129 | + minu_stamp=struct_time.tm_min, | |
130 | + d_minu_stamp=1 if d_minu_stamp == 0 else d_minu_stamp, | |
131 | + f_minu_stamp=1 if f_minu_stamp == 0 else f_minu_stamp) | |
132 | + | |
133 | + sys_session.add(monitor_log) | |
134 | + sys_session.commit() | |
135 | + | |
136 | + # for line in stdout: | |
137 | + # data = json.loads(line) | |
138 | + # # print(type(data)) | |
139 | + # print(data) | |
140 | + except Exception as e: | |
141 | + sys_session.rollback() | |
142 | + except e: | |
143 | + print('发生了异常:', e) | |
144 | + finally: | |
145 | + client.close() | |
146 | + if sys_session: | |
147 | + sys_session.close() | |
148 | + if sys_ds: | |
149 | + sys_ds.Destroy() | |
150 | + | |
151 | + | |
152 | +# 记录30条记录 | |
153 | +logs = [] | |
154 | + | |
155 | + | |
156 | +def start_schedule(): | |
157 | + # # 1分钟巡检一次 | |
158 | + schedule.every(2).minutes.do(background_job) | |
159 | + # schedule.every(5).seconds.do(background_job) | |
160 | + stop_run_continuously = run_continuously() | |
161 | + # Do some other things... | |
162 | + # # Stop the background thread | |
163 | + # time.sleep(10) | |
164 | + # stop_run_continuously.set() | |
165 | + | |
166 | + | |
167 | +def format_value(value): | |
168 | + # 1024*1024*1024 | |
169 | + if value > 1_073_741_824: | |
170 | + value = "{}GB".format(format(value/1_073_741_824, '.1f')) | |
171 | + elif value > 1_048_576: | |
172 | + # 1024*1024 | |
173 | + value = "{}MB".format(format(value / 1_048_576, '.1f')) | |
174 | + elif value > 1024: | |
175 | + value = "{}KB".format(format(value / 1024.0, '.1f')) | |
176 | + else: | |
177 | + value = "{}B".format(format(value, '.1f')) | |
178 | + return value | |
179 | + | |
180 | + | |
181 | +def Mb_format_value(value): | |
182 | + if value > 1024: | |
183 | + value = "{}GB".format(format(value/1024, '.1f')) | |
184 | + else: | |
185 | + value = "{}MB".format(format(value, '.1f')) | |
186 | + return value | ... | ... |
app/util/component/RunContinuous.py
0 → 100644
1 | +import schedule | |
2 | +import threading | |
3 | +import time | |
4 | + | |
5 | +##多线程类 | |
6 | +def run_continuously(interval=1): | |
7 | + """Continuously run, while executing pending jobs at each | |
8 | + elapsed time interval. | |
9 | + @return cease_continuous_run: threading. Event which can | |
10 | + be set to cease continuous run. Please note that it is | |
11 | + *intended behavior that run_continuously() does not run | |
12 | + missed jobs*. For example, if you've registered a job that | |
13 | + should run every minute and you set a continuous run | |
14 | + interval of one hour then your job won't be run 60 times | |
15 | + at each interval but only once. | |
16 | + """ | |
17 | + cease_continuous_run = threading.Event() | |
18 | + | |
19 | + class ScheduleThread(threading.Thread): | |
20 | + @classmethod | |
21 | + def run(cls): | |
22 | + while not cease_continuous_run.is_set(): | |
23 | + schedule.run_pending() | |
24 | + time.sleep(interval) | |
25 | + | |
26 | + continuous_thread = ScheduleThread() | |
27 | + #启动 | |
28 | + continuous_thread.start() | |
29 | + return cease_continuous_run | |
\ No newline at end of file | ... | ... |
... | ... | @@ -4,10 +4,12 @@ import logging |
4 | 4 | deploy_ip_host = "172.26.40.105:8840" |
5 | 5 | # 系统数据库 |
6 | 6 | |
7 | + | |
7 | 8 | # SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.100:5432/dmap_manager_test" |
8 | 9 | SQLALCHEMY_DATABASE_URI = "postgresql://postgres:chinadci@172.26.60.100:5432/dmap_manager" |
9 | 10 | # SQLALCHEMY_DATABASE_URI = "postgresql://postgres:postgres@localhost:5433/dmap_dms_test" |
10 | 11 | |
12 | + | |
11 | 13 | # 指定精华表所在位置(必须为空间库),设置为None则存放在各自的实体库中 |
12 | 14 | #VACUATE_DB_URI = None |
13 | 15 | VACUATE_DB_URI = SQLALCHEMY_DATABASE_URI | ... | ... |
... | ... | @@ -2,8 +2,11 @@ |
2 | 2 | from flask import Flask |
3 | 3 | from app import create_app |
4 | 4 | import os |
5 | +from app.modules.monitor.schedule import start_schedule | |
6 | + | |
5 | 7 | os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1' |
6 | 8 | app: Flask = create_app() |
7 | 9 | if __name__ == '__main__': |
10 | + # start_schedule() | |
8 | 11 | app.run(host="0.0.0.0", port="8840", threaded=True, debug=True) |
9 | 12 | # app.run(host="0.0.0.0", port="8840", threaded=True) | ... | ... |
请
注册
或
登录
后发表评论