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/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