ezKit 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ezKit/__init__.py +1 -0
- ezKit/bottle.py +3809 -0
- ezKit/cipher.py +74 -0
- ezKit/database.py +168 -0
- ezKit/files.py +348 -0
- ezKit/http.py +92 -0
- ezKit/mongo.py +62 -0
- ezKit/plots.py +155 -0
- ezKit/redis.py +51 -0
- ezKit/reports.py +274 -0
- ezKit/sendemail.py +146 -0
- ezKit/utils.py +1257 -0
- ezKit/weixin.py +148 -0
- ezKit/xftp.py +194 -0
- ezKit/zabbix.py +866 -0
- ezKit-1.0.0.dist-info/LICENSE +674 -0
- ezKit-1.0.0.dist-info/METADATA +10 -0
- ezKit-1.0.0.dist-info/RECORD +20 -0
- ezKit-1.0.0.dist-info/WHEEL +5 -0
- ezKit-1.0.0.dist-info/top_level.txt +1 -0
ezKit/zabbix.py
ADDED
@@ -0,0 +1,866 @@
|
|
1
|
+
import time
|
2
|
+
from copy import deepcopy
|
3
|
+
|
4
|
+
import requests
|
5
|
+
from loguru import logger
|
6
|
+
|
7
|
+
from .utils import list_dict_sorted_by_key, v_true
|
8
|
+
|
9
|
+
|
10
|
+
class Zabbix(object):
|
11
|
+
''' API '''
|
12
|
+
|
13
|
+
''' Zabbix API URL, User Login Result '''
|
14
|
+
api, auth = None, None
|
15
|
+
|
16
|
+
'''
|
17
|
+
https://www.zabbix.com/documentation/current/en/manual/api#performing-requests
|
18
|
+
The request must have the Content-Type header set to one of these values:
|
19
|
+
application/json-rpc, application/json or application/jsonrequest.
|
20
|
+
'''
|
21
|
+
_header = {'Content-Type': 'application/json-rpc'}
|
22
|
+
|
23
|
+
def __init__(self, api, username, password):
|
24
|
+
''' Initiation '''
|
25
|
+
try:
|
26
|
+
self.api = api
|
27
|
+
response: dict = self.request('user.login', {'username': username, 'password': password})
|
28
|
+
if v_true(response, dict) and response.get('result'):
|
29
|
+
self.auth = response['result']
|
30
|
+
except Exception as e:
|
31
|
+
logger.exception(e)
|
32
|
+
|
33
|
+
def request(self, method, params=None, **kwargs):
|
34
|
+
'''
|
35
|
+
Request Data
|
36
|
+
|
37
|
+
https://www.zabbix.com/documentation/current/en/manual/api#authentication
|
38
|
+
|
39
|
+
id - an arbitrary identifier of the request
|
40
|
+
id - 请求标识符, 这里使用UNIX时间戳作为唯一标示
|
41
|
+
'''
|
42
|
+
try:
|
43
|
+
_data = {
|
44
|
+
'jsonrpc': '2.0',
|
45
|
+
'method': method,
|
46
|
+
'params': params,
|
47
|
+
'auth': self.auth,
|
48
|
+
'id': int(time.time())
|
49
|
+
}
|
50
|
+
_response = requests.post(self.api, headers=self._header, json=_data, timeout=10, **kwargs)
|
51
|
+
return _response.json()
|
52
|
+
except Exception as e:
|
53
|
+
logger.exception(e)
|
54
|
+
return None
|
55
|
+
|
56
|
+
def logout(self):
|
57
|
+
'''User Logout'''
|
58
|
+
try:
|
59
|
+
return self.request('user.logout', [])
|
60
|
+
except Exception as e:
|
61
|
+
logger.exception(e)
|
62
|
+
return None
|
63
|
+
|
64
|
+
def logout_exit(self, str='Error'):
|
65
|
+
'''Logout and Exit'''
|
66
|
+
logger.info(str)
|
67
|
+
try:
|
68
|
+
self.logout()
|
69
|
+
except Exception as e:
|
70
|
+
logger.exception(e)
|
71
|
+
exit(1)
|
72
|
+
exit(1)
|
73
|
+
|
74
|
+
def get_ids_by_template_name(self, name='', **kwargs):
|
75
|
+
'''
|
76
|
+
Get ids by template name
|
77
|
+
|
78
|
+
name: string/array
|
79
|
+
example: 'Linux by Zabbix agent' / ['Linux by Zabbix agent', 'Linux by Zabbix agent active']
|
80
|
+
|
81
|
+
如果 name 为 '' (空), 返回所有 template id
|
82
|
+
'''
|
83
|
+
|
84
|
+
if self.auth == None:
|
85
|
+
logger.error('not authorized')
|
86
|
+
return None
|
87
|
+
|
88
|
+
try:
|
89
|
+
_response = self.request('template.get', {'output': 'templateid', 'filter': {'name': name}})
|
90
|
+
if v_true(_response, dict) and v_true(_response['result'], list):
|
91
|
+
return [i['templateid'] for i in _response['result']]
|
92
|
+
else:
|
93
|
+
return None
|
94
|
+
except Exception as e:
|
95
|
+
logger.exception(e)
|
96
|
+
return None
|
97
|
+
|
98
|
+
def get_ids_by_hostgroup_name(self, name='', **kwargs):
|
99
|
+
'''
|
100
|
+
Get ids by hostgroup name
|
101
|
+
|
102
|
+
name: string/array
|
103
|
+
example: 'Linux servers' / ['Linux servers', 'Discovered hosts']
|
104
|
+
|
105
|
+
如果 name 为 '' (空), 返回所有 hostgroup id
|
106
|
+
'''
|
107
|
+
|
108
|
+
if self.auth == None:
|
109
|
+
logger.error('not authorized')
|
110
|
+
return None
|
111
|
+
|
112
|
+
try:
|
113
|
+
_response = self.request('hostgroup.get', {'output': 'groupid', 'filter': {'name': name}})
|
114
|
+
if v_true(_response, dict) and v_true(_response.get('result', []), list):
|
115
|
+
return [i['groupid'] for i in _response['result']]
|
116
|
+
else:
|
117
|
+
return None
|
118
|
+
except Exception as e:
|
119
|
+
logger.exception(e)
|
120
|
+
return None
|
121
|
+
|
122
|
+
def get_hosts_by_template_name(self, name='', output='extend', **kwargs):
|
123
|
+
'''
|
124
|
+
Get hosts by template name
|
125
|
+
|
126
|
+
name: string/array
|
127
|
+
example: 'Linux by Zabbix agent' / ['Linux by Zabbix agent', 'Linux by Zabbix agent active']
|
128
|
+
|
129
|
+
如果 name 为 '' (空), 返回所有 host
|
130
|
+
'''
|
131
|
+
|
132
|
+
if self.auth == None:
|
133
|
+
logger.error('not authorized')
|
134
|
+
return None
|
135
|
+
|
136
|
+
try:
|
137
|
+
_response = self.request('template.get', {'output': ['templateid'], 'filter': {'host': name}})
|
138
|
+
if v_true(_response, dict) and v_true(_response.get('result', []), list):
|
139
|
+
_ids = [i['templateid'] for i in _response['result']]
|
140
|
+
_hosts = self.request('host.get', {'output': output, 'templateids': _ids, **kwargs})
|
141
|
+
if v_true(_hosts, dict) and v_true(_hosts.get('result', []), list):
|
142
|
+
return _hosts['result']
|
143
|
+
else:
|
144
|
+
return None
|
145
|
+
else:
|
146
|
+
return None
|
147
|
+
except Exception as e:
|
148
|
+
logger.exception(e)
|
149
|
+
return None
|
150
|
+
|
151
|
+
def get_hosts_by_hostgroup_name(self, name='', output='extend', **kwargs):
|
152
|
+
'''
|
153
|
+
Get hosts by hostgroup name
|
154
|
+
|
155
|
+
name: string/array
|
156
|
+
example: 'Linux servers' / ['Linux servers', 'Discovered hosts']
|
157
|
+
|
158
|
+
如果 name 为 '' (空), 返回所有 hosts
|
159
|
+
'''
|
160
|
+
|
161
|
+
if self.auth == None:
|
162
|
+
logger.error('not authorized')
|
163
|
+
return None
|
164
|
+
|
165
|
+
try:
|
166
|
+
_ids = self.get_ids_by_hostgroup_name(name)
|
167
|
+
if _ids == []:
|
168
|
+
return None
|
169
|
+
_hosts = self.request('host.get', {'output': output, 'groupids': _ids, **kwargs})
|
170
|
+
if v_true(_hosts, dict) and v_true(_hosts.get('result', []), list):
|
171
|
+
return _hosts['result']
|
172
|
+
else:
|
173
|
+
return None
|
174
|
+
except Exception as e:
|
175
|
+
logger.exception(e)
|
176
|
+
return None
|
177
|
+
|
178
|
+
def get_interface_by_host_id(self, hostid='', output='extend', **kwargs):
|
179
|
+
'''
|
180
|
+
Get interface by host id
|
181
|
+
|
182
|
+
hostids: string/array
|
183
|
+
example: '10792' / ['10792', '10793']
|
184
|
+
|
185
|
+
如果 name 为 '' (空), 则返回 []
|
186
|
+
'''
|
187
|
+
|
188
|
+
if self.auth == None:
|
189
|
+
logger.error('not authorized')
|
190
|
+
return None
|
191
|
+
|
192
|
+
try:
|
193
|
+
_response = self.request('hostinterface.get', {'output': output, 'hostids': hostid})
|
194
|
+
if v_true(_response, dict) and v_true(_response.get('result', []), list):
|
195
|
+
return _response['result']
|
196
|
+
else:
|
197
|
+
return None
|
198
|
+
except Exception as e:
|
199
|
+
logger.exception(e)
|
200
|
+
return None
|
201
|
+
|
202
|
+
def available_hosts(self, hosts=[], **kwargs):
|
203
|
+
'''可用服务器'''
|
204
|
+
|
205
|
+
if self.auth == None:
|
206
|
+
logger.error('not authorized')
|
207
|
+
return None
|
208
|
+
|
209
|
+
try:
|
210
|
+
|
211
|
+
# 可用服务器, 不可用服务器
|
212
|
+
_available_hosts, _unavailable_hosts = [], []
|
213
|
+
|
214
|
+
# 服务器排查
|
215
|
+
for _host in hosts:
|
216
|
+
if _host['interfaces'][0]['available'] != '1':
|
217
|
+
_unavailable_hosts.append(_host['name'])
|
218
|
+
else:
|
219
|
+
_available_hosts.append(_host)
|
220
|
+
|
221
|
+
return _available_hosts, _unavailable_hosts
|
222
|
+
|
223
|
+
except Exception as e:
|
224
|
+
logger.exception(e)
|
225
|
+
return None
|
226
|
+
|
227
|
+
def get_history_by_item_key(self, hosts=[], time_from=0, time_till=0, item_key='', data_type=3, **kwargs):
|
228
|
+
'''
|
229
|
+
1. 根据 item key 获取 item id, 通过 item id 获取 history
|
230
|
+
2. 根据 host 的 item id 和 history 的 item id 将数据提取为一个 history list
|
231
|
+
3. 根据 history list 中的 clock 排序, 然后将 history list 整合到 host 中
|
232
|
+
4. 返回包含有 item key, item id 和 history list 的 host 的 host list
|
233
|
+
|
234
|
+
通过 Item Key 获取 Item history
|
235
|
+
|
236
|
+
hosts: 主机列表
|
237
|
+
time_from: 开始时间
|
238
|
+
time_till: 结束时间
|
239
|
+
item_key: Item Key
|
240
|
+
data_type: 数据类型
|
241
|
+
|
242
|
+
参考文档:
|
243
|
+
|
244
|
+
https://www.zabbix.com/documentation/6.0/en/manual/api/reference/history/get
|
245
|
+
|
246
|
+
history
|
247
|
+
|
248
|
+
0 - numeric float
|
249
|
+
1 - character
|
250
|
+
2 - log
|
251
|
+
3 - numeric unsigned
|
252
|
+
4 - text
|
253
|
+
|
254
|
+
Default: 3
|
255
|
+
|
256
|
+
默认数据类型是 numeric unsigned (整数), 如果 history.get 返回的数据为 None, 有可能是 data_type 类型不对
|
257
|
+
'''
|
258
|
+
|
259
|
+
if self.auth == None:
|
260
|
+
logger.error('not authorized')
|
261
|
+
return None
|
262
|
+
|
263
|
+
try:
|
264
|
+
|
265
|
+
match True:
|
266
|
+
case True if type(hosts) != list or hosts == []:
|
267
|
+
logger.error('ERROR!! hosts is not list or none')
|
268
|
+
return None
|
269
|
+
case True if type(time_from) != int or time_from == 0:
|
270
|
+
logger.error('ERROR!! time_from is not integer or zero')
|
271
|
+
return None
|
272
|
+
case True if type(time_till) != int or time_till == 0:
|
273
|
+
logger.error('ERROR!! time_till is not integer or zero')
|
274
|
+
return None
|
275
|
+
case True if type(item_key) != str or item_key == '':
|
276
|
+
logger.error('ERROR!! item_key is not string or none')
|
277
|
+
return None
|
278
|
+
|
279
|
+
# 初始化变量
|
280
|
+
# _item_ids 获取历史数据时使用
|
281
|
+
# _item_history 历史数据集合, 最后返回
|
282
|
+
_item_ids, _item_history = [], []
|
283
|
+
|
284
|
+
'''
|
285
|
+
Deep Copy (拷贝数据)
|
286
|
+
父函数的变量是 list 或者 dict 类型, 父函数将变量传递个子函数, 如果子函数对变量数据进行了修改, 那么父函数的变量的数据也会被修改
|
287
|
+
为了避免出现这种问题, 可以使用 Deep Copy 拷贝一份数据, 避免子函数修改父函数的变量的数据
|
288
|
+
'''
|
289
|
+
_hosts = deepcopy(hosts)
|
290
|
+
|
291
|
+
# --------------------------------------------------------------------------------------------------
|
292
|
+
|
293
|
+
# Get Item
|
294
|
+
_hostids = [i['hostid'] for i in _hosts]
|
295
|
+
_item_params = {
|
296
|
+
'output': ['name', 'itemid', 'hostid'],
|
297
|
+
'hostids': _hostids,
|
298
|
+
'filter': {'key_': item_key}
|
299
|
+
}
|
300
|
+
_items = self.request('item.get', _item_params)
|
301
|
+
|
302
|
+
# --------------------------------------------------------------------------------------------------
|
303
|
+
|
304
|
+
# 因为 history 获取的顺序是乱的, 为了使输出和 hosts 列表顺序一致, 将 Item ID 追加到 hosts, 然后遍历 hosts 列表输出
|
305
|
+
if v_true(_items, dict) and v_true(_items.get('result', []), list):
|
306
|
+
for _host in _hosts:
|
307
|
+
_item = next((_item_object for _item_object in _items['result'] if _host['hostid'] == _item_object['hostid']), '')
|
308
|
+
if v_true(_item, dict) and _item.get('itemid') != None:
|
309
|
+
_host['itemkey'] = item_key
|
310
|
+
_host['itemid'] = _item['itemid']
|
311
|
+
_item_ids.append(_item['itemid'])
|
312
|
+
_item_history.append(_host)
|
313
|
+
else:
|
314
|
+
logger.error('ERROR!! item key {} not find'.format(item_key))
|
315
|
+
return None
|
316
|
+
|
317
|
+
# 如果 ID 列表为空, 则返回 None
|
318
|
+
if _item_ids == []:
|
319
|
+
logger.error('ERROR!! item key {} not find'.format(item_key))
|
320
|
+
return None
|
321
|
+
|
322
|
+
# --------------------------------------------------------------------------------------------------
|
323
|
+
|
324
|
+
# Get History
|
325
|
+
_history_params = {
|
326
|
+
'output': 'extend',
|
327
|
+
'history': data_type,
|
328
|
+
'itemids': _item_ids,
|
329
|
+
'time_from': time_from,
|
330
|
+
'time_till': time_till
|
331
|
+
}
|
332
|
+
_history = self.request('history.get', _history_params)
|
333
|
+
|
334
|
+
# --------------------------------------------------------------------------------------------------
|
335
|
+
|
336
|
+
if v_true(_history, dict) and v_true(_history.get('result', []), list):
|
337
|
+
|
338
|
+
for _item in _item_history:
|
339
|
+
# 根据 itemid 提取数据
|
340
|
+
_item_history_data = [_history_result for _history_result in _history['result'] if _item['itemid'] == _history_result['itemid']]
|
341
|
+
# 根据 clock 排序
|
342
|
+
_item_history_data = list_dict_sorted_by_key(_item_history_data, 'clock')
|
343
|
+
# 整合数据
|
344
|
+
_item['history'] = _item_history_data
|
345
|
+
|
346
|
+
return _item_history
|
347
|
+
|
348
|
+
else:
|
349
|
+
|
350
|
+
logger.error('ERROR!! item history not find')
|
351
|
+
return None
|
352
|
+
|
353
|
+
except Exception as e:
|
354
|
+
logger.exception(e)
|
355
|
+
return None
|
356
|
+
|
357
|
+
def get_history_by_interface(self, hosts=[], interfaces=[], time_from=0, time_till=0, direction='', **kwargs):
|
358
|
+
'''获取网卡历史数据'''
|
359
|
+
|
360
|
+
if self.auth == None:
|
361
|
+
logger.error('not authorized')
|
362
|
+
return None
|
363
|
+
|
364
|
+
try:
|
365
|
+
|
366
|
+
match True:
|
367
|
+
case True if type(hosts) != list or hosts == []:
|
368
|
+
logger.error('ERROR!! hosts is not list or none')
|
369
|
+
return None
|
370
|
+
case True if type(interfaces) != list or interfaces == []:
|
371
|
+
logger.error('ERROR!! interfaces is not list or none')
|
372
|
+
return None
|
373
|
+
case True if type(time_from) != int or time_from == 0:
|
374
|
+
logger.error('ERROR!! time_from is not integer or zero')
|
375
|
+
return None
|
376
|
+
case True if type(time_till) != int or time_till == 0:
|
377
|
+
logger.error('ERROR!! time_till is not integer or zero')
|
378
|
+
return None
|
379
|
+
case True if type(direction) != str or direction == '':
|
380
|
+
logger.error('ERROR!! direction is not string or none')
|
381
|
+
return None
|
382
|
+
|
383
|
+
# 创建一个只有 网卡名称 的 list
|
384
|
+
_interfaces_names = list(set(_interface['interface'] for _interface in interfaces))
|
385
|
+
|
386
|
+
# 创建一个 Key 为 网卡名称 的 dictionary
|
387
|
+
_interfaces_dict = {_key: [] for _key in _interfaces_names}
|
388
|
+
|
389
|
+
# 汇集 相同网卡名称 的 IP
|
390
|
+
for _interface in interfaces:
|
391
|
+
_interfaces_dict[_interface['interface']].append(_interface['host'])
|
392
|
+
|
393
|
+
# 获取历史数据
|
394
|
+
_history = []
|
395
|
+
for _key, _value in _interfaces_dict.items():
|
396
|
+
_hosts_by_ip = [_host for _v in _value for _host in hosts if _v == _host['interfaces'][0]['ip']]
|
397
|
+
_history += self.get_history_by_item_key(
|
398
|
+
hosts=_hosts_by_ip,
|
399
|
+
time_from=time_from,
|
400
|
+
time_till=time_till,
|
401
|
+
item_key='net.if.{}["{}"]'.format(direction, _key),
|
402
|
+
data_type=3
|
403
|
+
)
|
404
|
+
|
405
|
+
# 根据 name 排序
|
406
|
+
_history = list_dict_sorted_by_key(_history, 'name')
|
407
|
+
|
408
|
+
return _history
|
409
|
+
|
410
|
+
except Exception as e:
|
411
|
+
logger.exception(e)
|
412
|
+
return None
|
413
|
+
|
414
|
+
def create_process_object(self, ips=[], name='', item_type=0, proc_name='', proc_user='', proc_cmdline='', ignore_cpu=False, ignore_mem=False, **kwargs) -> bool:
|
415
|
+
'''
|
416
|
+
创建进程对象
|
417
|
+
|
418
|
+
ips: IP列表
|
419
|
+
name: 名称 (Item, Trigger, Graph 的名称前缀)
|
420
|
+
item_type: Item Type (默认 0: Zabbix agent)
|
421
|
+
proc_name: 进程名称
|
422
|
+
proc_user: 进程用户
|
423
|
+
proc_cmdline: 进程参数
|
424
|
+
ignore_cpu: 是否创建 CPU Item 和 Graph
|
425
|
+
ignore_mem: 是否创建 Memory Item 和 Graph
|
426
|
+
|
427
|
+
参考文档:
|
428
|
+
|
429
|
+
https://www.zabbix.com/documentation/6.0/en/manual/api/reference/item/object
|
430
|
+
https://www.zabbix.com/documentation/6.0/en/manual/config/items/itemtypes/zabbix_agent#process-data
|
431
|
+
|
432
|
+
type:
|
433
|
+
|
434
|
+
0 - Zabbix agent;
|
435
|
+
2 - Zabbix trapper;
|
436
|
+
3 - Simple check;
|
437
|
+
5 - Zabbix internal;
|
438
|
+
7 - Zabbix agent (active);
|
439
|
+
9 - Web item;
|
440
|
+
10 - External check;
|
441
|
+
11 - Database monitor;
|
442
|
+
12 - IPMI agent;
|
443
|
+
13 - SSH agent;
|
444
|
+
14 - Telnet agent;
|
445
|
+
15 - Calculated;
|
446
|
+
16 - JMX agent;
|
447
|
+
17 - SNMP trap;
|
448
|
+
18 - Dependent item;
|
449
|
+
19 - HTTP agent;
|
450
|
+
20 - SNMP agent;
|
451
|
+
21 - Script
|
452
|
+
|
453
|
+
value_type:
|
454
|
+
|
455
|
+
0 - numeric float;
|
456
|
+
1 - character;
|
457
|
+
2 - log;
|
458
|
+
3 - numeric unsigned;
|
459
|
+
4 - text.
|
460
|
+
|
461
|
+
测试:
|
462
|
+
|
463
|
+
zabbix_get -s 47.109.22.195 -p 10050 -k 'proc.num[java,karakal,,server.port=8011]'
|
464
|
+
zabbix_get -s 47.109.22.195 -p 10050 -k 'proc.cpu.util[java,karakal,,server.port=8011]'
|
465
|
+
zabbix_get -s 47.109.22.195 -p 10050 -k 'proc.mem[java,karakal,,server.port=8011,rss]'
|
466
|
+
zabbix_get -s 47.109.22.195 -p 10050 -k 'proc.mem[java,karakal,,server.port=8011,pmem]'
|
467
|
+
|
468
|
+
Memory used (rss) 的值除以 1024 就和 Zabbix Web 显示的一样了
|
469
|
+
|
470
|
+
创建 Item:
|
471
|
+
|
472
|
+
Number of processes 进程数量
|
473
|
+
CPU utilization CPU使用率
|
474
|
+
Memory used (rss) 内存使用量
|
475
|
+
Memory used (pmem) 内存使用率
|
476
|
+
|
477
|
+
value type:
|
478
|
+
|
479
|
+
Number of processes 3
|
480
|
+
CPU utilization 0
|
481
|
+
Memory used (rss) 0
|
482
|
+
Memory used (pmem) 0
|
483
|
+
|
484
|
+
获取 Item history 时, 如果返回结果为 None, 有可能是 value type 不一致
|
485
|
+
|
486
|
+
创建 Trigger:
|
487
|
+
|
488
|
+
Number of processes 如果进程数量为 0, 表示进程不存在 (应用或服务挂了)
|
489
|
+
|
490
|
+
创建 Graph:
|
491
|
+
|
492
|
+
CPU utilization CPU使用率
|
493
|
+
Memory used (rss) 内存使用量
|
494
|
+
Memory used (pmem) 内存使用率
|
495
|
+
|
496
|
+
如果创建 Graph 后显示 [no data], 可以在 Items 中进入对应的 Item, 然后点击最下方的 Latest data
|
497
|
+
在 Latest data 的右边的 Info 下面会有黄色感叹号, 将鼠标移动到上面, 可以看到相关的提示
|
498
|
+
'''
|
499
|
+
|
500
|
+
if self.auth == None:
|
501
|
+
logger.error('not authorized')
|
502
|
+
return None
|
503
|
+
|
504
|
+
try:
|
505
|
+
|
506
|
+
match True:
|
507
|
+
case True if type(ips) != list or ips == []:
|
508
|
+
logger.error('ERROR!! ips is not list or none')
|
509
|
+
return False
|
510
|
+
case True if type(name) != str or name == '':
|
511
|
+
logger.error('ERROR!! name is not string or none')
|
512
|
+
return False
|
513
|
+
case True if type(proc_name) != str or proc_name == '':
|
514
|
+
logger.error('ERROR!! proc_name is not string or none')
|
515
|
+
return False
|
516
|
+
|
517
|
+
# The number of processes
|
518
|
+
# proc.num[<name>,<user>,<state>,<cmdline>,<zone>]
|
519
|
+
_proc_num_item_name = '{} Number of processes'.format(name)
|
520
|
+
_proc_num_item_key = 'proc.num[{},{},,{}]'.format(proc_name, proc_user, proc_cmdline)
|
521
|
+
|
522
|
+
_proc_num_trigger_name = '{} is down'.format(name)
|
523
|
+
|
524
|
+
# Process CPU utilization percentage
|
525
|
+
# proc.cpu.util[<name>,<user>,<type>,<cmdline>,<mode>,<zone>]
|
526
|
+
_proc_cpu_util_item_name = '{} CPU utilization'.format(name)
|
527
|
+
_proc_cpu_util_item_key = 'proc.cpu.util[{},{},,{}]'.format(proc_name, proc_user, proc_cmdline)
|
528
|
+
|
529
|
+
# Memory used by process in bytes
|
530
|
+
# https://www.zabbix.com/documentation/6.0/en/manual/appendix/items/proc_mem_notes
|
531
|
+
# proc.mem[<name>,<user>,<mode>,<cmdline>,<memtype>]
|
532
|
+
# pmem: 内存使用量百分比, 即 top 显示的百分比
|
533
|
+
# rss: 内存使用量实际数值, 即 总内存 x pmem(百分比)
|
534
|
+
# Value Type 要使用 numeric float, 即 0, 否则会报错:
|
535
|
+
# Value of type 'string' is not suitable for value type 'Numeric (unsigned)'.
|
536
|
+
_proc_mem_rss_item_name = '{} Memory used (rss)'.format(name)
|
537
|
+
_proc_mem_rss_item_key = 'proc.mem[{},{},,{},rss]'.format(proc_name, proc_user, proc_cmdline)
|
538
|
+
|
539
|
+
_proc_mem_pmem_item_name = '{} Memory used (pmem)'.format(name)
|
540
|
+
_proc_mem_pmem_item_key = 'proc.mem[{},{},,{},pmem]'.format(proc_name, proc_user, proc_cmdline)
|
541
|
+
|
542
|
+
# Create Item, Trigger, Graph
|
543
|
+
for _ip in ips:
|
544
|
+
|
545
|
+
# Host Info
|
546
|
+
_hostinterface = self.request('hostinterface.get', {'filter': {'ip': _ip}, 'selectHosts': ['host']})
|
547
|
+
_host = _hostinterface['result'][0]['hosts'][0]['host']
|
548
|
+
_host_id = _hostinterface['result'][0]['hostid']
|
549
|
+
_interface_id = _hostinterface['result'][0]['interfaceid']
|
550
|
+
|
551
|
+
# --------------------------------------------------------------------------------------------------
|
552
|
+
|
553
|
+
# Number of processes
|
554
|
+
|
555
|
+
# Create Item
|
556
|
+
_params = {
|
557
|
+
'name': _proc_num_item_name,
|
558
|
+
'key_': _proc_num_item_key,
|
559
|
+
'hostid': _host_id,
|
560
|
+
'type': item_type,
|
561
|
+
'value_type': 3,
|
562
|
+
'interfaceid': _interface_id,
|
563
|
+
'delay': '1m',
|
564
|
+
'history': '7d',
|
565
|
+
'trends': '7d'
|
566
|
+
}
|
567
|
+
_ = self.request('item.create', _params)
|
568
|
+
logger.success(_)
|
569
|
+
|
570
|
+
# Create Trigger
|
571
|
+
_params = [
|
572
|
+
{
|
573
|
+
'description': _proc_num_trigger_name,
|
574
|
+
'priority': '2',
|
575
|
+
'expression': 'last(/{}/{})=0'.format(_host, _proc_num_item_key),
|
576
|
+
'manual_close': '1'
|
577
|
+
}
|
578
|
+
]
|
579
|
+
_ = self.request('trigger.create', _params)
|
580
|
+
logger.success(_)
|
581
|
+
|
582
|
+
# --------------------------------------------------------------------------------------------------
|
583
|
+
|
584
|
+
# CPU utilization
|
585
|
+
|
586
|
+
if ignore_cpu == False:
|
587
|
+
|
588
|
+
# Create Item
|
589
|
+
_params = {
|
590
|
+
'name': _proc_cpu_util_item_name,
|
591
|
+
'key_': _proc_cpu_util_item_key,
|
592
|
+
'hostid': _host_id,
|
593
|
+
'type': item_type,
|
594
|
+
'value_type': 0,
|
595
|
+
'interfaceid': _interface_id,
|
596
|
+
'delay': '1m',
|
597
|
+
'history': '7d',
|
598
|
+
'trends': '7d'
|
599
|
+
}
|
600
|
+
_ = self.request('item.create', _params)
|
601
|
+
logger.success(_)
|
602
|
+
|
603
|
+
# Item Info
|
604
|
+
_item_params = {
|
605
|
+
'output': 'itemid',
|
606
|
+
'hostids': _host_id,
|
607
|
+
'filter': {'key_': _proc_cpu_util_item_key}
|
608
|
+
}
|
609
|
+
_item = self.request('item.get', _item_params)
|
610
|
+
_item_id = _item['result'][0]['itemid']
|
611
|
+
|
612
|
+
# Create Graph
|
613
|
+
_graph_params = {
|
614
|
+
'name': _proc_cpu_util_item_name,
|
615
|
+
'width': 900,
|
616
|
+
'height': 200,
|
617
|
+
'yaxismin': 0,
|
618
|
+
'yaxismax': 100,
|
619
|
+
'ymin_type': 1,
|
620
|
+
'ymax_type': 1,
|
621
|
+
'gitems': [{'itemid': _item_id, 'color': '0040FF'}]
|
622
|
+
}
|
623
|
+
_ = self.request('graph.create', _graph_params)
|
624
|
+
logger.success(_)
|
625
|
+
|
626
|
+
# --------------------------------------------------------------------------------------------------
|
627
|
+
|
628
|
+
# Memory used
|
629
|
+
|
630
|
+
if ignore_mem == False:
|
631
|
+
|
632
|
+
# Memory used (rss)
|
633
|
+
|
634
|
+
# Create Item
|
635
|
+
_params = {
|
636
|
+
'name': _proc_mem_rss_item_name,
|
637
|
+
'key_': _proc_mem_rss_item_key,
|
638
|
+
'hostid': _host_id,
|
639
|
+
'type': item_type,
|
640
|
+
'value_type': 0,
|
641
|
+
'interfaceid': _interface_id,
|
642
|
+
'delay': '1m',
|
643
|
+
'history': '7d',
|
644
|
+
'trends': '7d'
|
645
|
+
}
|
646
|
+
_ = self.request('item.create', _params)
|
647
|
+
logger.success(_)
|
648
|
+
|
649
|
+
# Total memory
|
650
|
+
_vm_params = {
|
651
|
+
'output': 'itemid',
|
652
|
+
'hostids': _host_id,
|
653
|
+
'filter': {'key_': 'vm.memory.size[total]'}
|
654
|
+
}
|
655
|
+
_vm_total = self.request('item.get', _vm_params)
|
656
|
+
_vm_total_itemid = _vm_total['result'][0]['itemid']
|
657
|
+
|
658
|
+
# Item Info
|
659
|
+
_item_params = {
|
660
|
+
'output': 'itemid',
|
661
|
+
'hostids': _host_id,
|
662
|
+
'filter': {'key_': _proc_mem_rss_item_key}
|
663
|
+
}
|
664
|
+
_item = self.request('item.get', _item_params)
|
665
|
+
_item_id = _item['result'][0]['itemid']
|
666
|
+
|
667
|
+
# Create Graph
|
668
|
+
# gitems 需要注意顺序
|
669
|
+
_graph_params = {
|
670
|
+
'name': _proc_mem_rss_item_name,
|
671
|
+
'width': 900,
|
672
|
+
'height': 200,
|
673
|
+
'graphtype': 1,
|
674
|
+
'gitems': [
|
675
|
+
{'itemid': _item_id, 'color': '00FF00'},
|
676
|
+
{'itemid': _vm_total_itemid, 'color': '1E88E5'}
|
677
|
+
]
|
678
|
+
}
|
679
|
+
_ = self.request('graph.create', _graph_params)
|
680
|
+
logger.success(_)
|
681
|
+
|
682
|
+
# --------------------------------------------------------------------------------------------------
|
683
|
+
|
684
|
+
# Memory used (pmem)
|
685
|
+
|
686
|
+
# Create Item
|
687
|
+
# Units: %
|
688
|
+
_params = {
|
689
|
+
'name': _proc_mem_pmem_item_name,
|
690
|
+
'key_': _proc_mem_pmem_item_key,
|
691
|
+
'hostid': _host_id,
|
692
|
+
'type': item_type,
|
693
|
+
'value_type': 0,
|
694
|
+
'interfaceid': _interface_id,
|
695
|
+
'units': '%',
|
696
|
+
'delay': '1m',
|
697
|
+
'history': '7d',
|
698
|
+
'trends': '7d'
|
699
|
+
}
|
700
|
+
_ = self.request('item.create', _params)
|
701
|
+
logger.success(_)
|
702
|
+
|
703
|
+
# Item Info
|
704
|
+
_item_params = {
|
705
|
+
'output': 'itemid',
|
706
|
+
'hostids': _host_id,
|
707
|
+
'filter': {'key_': _proc_mem_pmem_item_key}
|
708
|
+
}
|
709
|
+
_item = self.request('item.get', _item_params)
|
710
|
+
_item_id = _item['result'][0]['itemid']
|
711
|
+
|
712
|
+
# Create Graph
|
713
|
+
_graph_params = {
|
714
|
+
'name': _proc_mem_pmem_item_name,
|
715
|
+
'width': 900,
|
716
|
+
'height': 200,
|
717
|
+
'graphtype': 1,
|
718
|
+
'yaxismin': 0,
|
719
|
+
'yaxismax': 100,
|
720
|
+
'ymin_type': 1,
|
721
|
+
'ymax_type': 1,
|
722
|
+
'gitems': [
|
723
|
+
{'itemid': _item_id, 'color': '66BB6A'}
|
724
|
+
]
|
725
|
+
}
|
726
|
+
_ = self.request('graph.create', _graph_params)
|
727
|
+
logger.success(_)
|
728
|
+
|
729
|
+
return True
|
730
|
+
|
731
|
+
except Exception as e:
|
732
|
+
logger.exception(e)
|
733
|
+
return False
|
734
|
+
|
735
|
+
def create_tcp_port_check(self, ips=None, name=None, item_type=0, ip=None, port=None, **kwargs) -> bool:
|
736
|
+
'''
|
737
|
+
创建进程对象
|
738
|
+
|
739
|
+
ips: IP列表
|
740
|
+
name: 名称 (Item, Trigger, Graph 的名称前缀)
|
741
|
+
item_type: Item Type (默认 0: Zabbix agent)
|
742
|
+
ip: IP地址
|
743
|
+
port: 目标端口
|
744
|
+
|
745
|
+
参考文档:
|
746
|
+
|
747
|
+
https://www.zabbix.com/documentation/6.0/en/manual/api/reference/item/object
|
748
|
+
https://www.zabbix.com/documentation/6.0/en/manual/config/items/itemtypes/zabbix_agent#network-data
|
749
|
+
|
750
|
+
type:
|
751
|
+
|
752
|
+
0 - Zabbix agent;
|
753
|
+
2 - Zabbix trapper;
|
754
|
+
3 - Simple check;
|
755
|
+
5 - Zabbix internal;
|
756
|
+
7 - Zabbix agent (active);
|
757
|
+
9 - Web item;
|
758
|
+
10 - External check;
|
759
|
+
11 - Database monitor;
|
760
|
+
12 - IPMI agent;
|
761
|
+
13 - SSH agent;
|
762
|
+
14 - Telnet agent;
|
763
|
+
15 - Calculated;
|
764
|
+
16 - JMX agent;
|
765
|
+
17 - SNMP trap;
|
766
|
+
18 - Dependent item;
|
767
|
+
19 - HTTP agent;
|
768
|
+
20 - SNMP agent;
|
769
|
+
21 - Script
|
770
|
+
|
771
|
+
value_type:
|
772
|
+
|
773
|
+
0 - numeric float;
|
774
|
+
1 - character;
|
775
|
+
2 - log;
|
776
|
+
3 - numeric unsigned;
|
777
|
+
4 - text.
|
778
|
+
|
779
|
+
测试:
|
780
|
+
|
781
|
+
zabbix_get -s 10.26.20.141 -p 20050 -k 'net.tcp.port[10.25.182.10,20051]'
|
782
|
+
|
783
|
+
创建 Item:
|
784
|
+
|
785
|
+
TCP connection 进程数量
|
786
|
+
|
787
|
+
value type:
|
788
|
+
|
789
|
+
TCP connection 3
|
790
|
+
|
791
|
+
获取 Item history 时, 如果返回结果为 None, 有可能是 value type 不一致
|
792
|
+
|
793
|
+
创建 Trigger:
|
794
|
+
|
795
|
+
TCP connection 结果如果为 0, 端口无法访问
|
796
|
+
'''
|
797
|
+
|
798
|
+
if self.auth == None:
|
799
|
+
logger.error('not authorized')
|
800
|
+
return None
|
801
|
+
|
802
|
+
try:
|
803
|
+
|
804
|
+
match True:
|
805
|
+
case True if type(ips) != list or ips == None:
|
806
|
+
logger.error('ERROR!! ips is not list or none')
|
807
|
+
return False
|
808
|
+
case True if type(name) != str or name == None:
|
809
|
+
logger.error('ERROR!! name is not string or none')
|
810
|
+
return False
|
811
|
+
case True if type(ip) != str or ip == None:
|
812
|
+
logger.error('ERROR!! ip is not string or none')
|
813
|
+
return False
|
814
|
+
case True if type(port) != int or port == None:
|
815
|
+
logger.error('ERROR!! port is not integer or none')
|
816
|
+
return False
|
817
|
+
|
818
|
+
# Checks if it is possible to make TCP connection to specified port.
|
819
|
+
# net.tcp.port[<ip>,port]
|
820
|
+
_item_name = 'TCP connection: {}'.format(name)
|
821
|
+
_item_key = 'net.tcp.port[{},{}]'.format(ip, port)
|
822
|
+
_trigger_name = 'Failed to connect to {} port {}'.format(ip, port)
|
823
|
+
|
824
|
+
# Create Item, Trigger
|
825
|
+
for _ip in ips:
|
826
|
+
|
827
|
+
# Host Info
|
828
|
+
_hostinterface = self.request('hostinterface.get', {'filter': {'ip': _ip}, 'selectHosts': ['host']})
|
829
|
+
_host = _hostinterface['result'][0]['hosts'][0]['host']
|
830
|
+
_host_id = _hostinterface['result'][0]['hostid']
|
831
|
+
_interface_id = _hostinterface['result'][0]['interfaceid']
|
832
|
+
|
833
|
+
# Create Item
|
834
|
+
_params = {
|
835
|
+
'name': _item_name,
|
836
|
+
'key_': _item_key,
|
837
|
+
'hostid': _host_id,
|
838
|
+
'type': item_type,
|
839
|
+
'value_type': 3,
|
840
|
+
'interfaceid': _interface_id,
|
841
|
+
'delay': '1m',
|
842
|
+
'history': '7d',
|
843
|
+
'trends': '7d'
|
844
|
+
}
|
845
|
+
_ = self.request('item.create', _params)
|
846
|
+
logger.success(_)
|
847
|
+
|
848
|
+
# Create Trigger
|
849
|
+
_expression = None
|
850
|
+
_expression = 'last(/{}/{})=0'.format(_host, _item_key)
|
851
|
+
_params = [
|
852
|
+
{
|
853
|
+
'description': _trigger_name,
|
854
|
+
'priority': '2',
|
855
|
+
'expression': _expression,
|
856
|
+
'manual_close': '1'
|
857
|
+
}
|
858
|
+
]
|
859
|
+
_ = self.request('trigger.create', _params)
|
860
|
+
logger.success(_)
|
861
|
+
|
862
|
+
return True
|
863
|
+
|
864
|
+
except Exception as e:
|
865
|
+
logger.exception(e)
|
866
|
+
return False
|