pytbox 0.1.8__tar.gz → 0.2.0__tar.gz
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.
Potentially problematic release.
This version of pytbox might be problematic. Click here for more details.
- {pytbox-0.1.8/src/pytbox.egg-info → pytbox-0.2.0}/PKG-INFO +1 -1
- {pytbox-0.1.8 → pytbox-0.2.0}/pyproject.toml +1 -1
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/alert/alert_handler.py +27 -7
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/base.py +4 -5
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/database/mongo.py +1 -1
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/database/victoriametrics.py +36 -2
- pytbox-0.2.0/src/pytbox/excel.py +64 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/mail/client.py +4 -0
- {pytbox-0.1.8 → pytbox-0.2.0/src/pytbox.egg-info}/PKG-INFO +1 -1
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_victoriametrics.py +7 -1
- pytbox-0.1.8/src/pytbox/excel.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/MANIFEST.in +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/README.md +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/setup.cfg +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/alert/ping.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/alicloud/sls.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/build_config.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/instances.toml +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.cpu/cpu.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.disk/disk.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.diskio/diskio.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.dns_query/dns_query.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.http_response/http_response.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.mem/mem.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.net/net.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.net_response/net_response.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.ping/ping.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/cisco_interface.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/cisco_system.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/h3c_interface.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/h3c_system.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/huawei_system.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/ruijie_system.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.vsphere/vsphere.toml.j2 +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/categraf/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/categraf/commands.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/commands/vm.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/common/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/common/options.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/common/utils.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/formatters/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/formatters/output.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli/main.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/cli.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/common/__init__.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/dida365.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/feishu/client.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/feishu/endpoints.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/feishu/errors.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/feishu/helpers.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/feishu/typing.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/log/logger.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/log/victorialog.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/mail/alimail.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/mail/mail_detail.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/network/meraki.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/onepassword_connect.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/onepassword_sa.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/pyjira.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/cronjob.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/env.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/load_config.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/load_vm_devfile.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/response.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/richutils.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/utils/timeutils.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/vmware.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/win/ad.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox.egg-info/SOURCES.txt +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox.egg-info/dependency_links.txt +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox.egg-info/entry_points.txt +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox.egg-info/requires.txt +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox.egg-info/top_level.txt +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_base.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_feishu.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_load_jsonfile.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_logger.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_onepassword_connect.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_onepassword_sa.py +0 -0
- {pytbox-0.1.8 → pytbox-0.2.0}/tests/test_vmware.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pytbox"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)"
|
|
9
9
|
authors = [{ name = "mingming hou", email = "houm01@foxmail.com" }]
|
|
10
10
|
license = "MIT"
|
|
@@ -7,6 +7,7 @@ from ..database.mongo import Mongo
|
|
|
7
7
|
from ..feishu.client import Client as FeishuClient
|
|
8
8
|
from ..dida365 import Dida365
|
|
9
9
|
from ..utils.timeutils import TimeUtils
|
|
10
|
+
from ..mail.client import MailClient
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class AlertHandler:
|
|
@@ -15,12 +16,17 @@ class AlertHandler:
|
|
|
15
16
|
config: dict=None,
|
|
16
17
|
mongo_client: Mongo=None,
|
|
17
18
|
feishu_client: FeishuClient=None,
|
|
18
|
-
dida_client: Dida365=None
|
|
19
|
+
dida_client: Dida365=None,
|
|
20
|
+
mail_client: MailClient=None,
|
|
21
|
+
env: Literal['dev', 'prod']='prod'
|
|
19
22
|
):
|
|
23
|
+
|
|
20
24
|
self.config = config
|
|
21
25
|
self.mongo = mongo_client
|
|
22
26
|
self.feishu = feishu_client
|
|
23
27
|
self.dida = dida_client
|
|
28
|
+
self.mail = mail_client
|
|
29
|
+
self.env = env
|
|
24
30
|
|
|
25
31
|
def send_alert(self,
|
|
26
32
|
event_id: str=None,
|
|
@@ -34,7 +40,7 @@ class AlertHandler:
|
|
|
34
40
|
suggestion: str='',
|
|
35
41
|
troubleshot: str='暂无',
|
|
36
42
|
mongo_id: str=None
|
|
37
|
-
|
|
43
|
+
):
|
|
38
44
|
|
|
39
45
|
if not event_id:
|
|
40
46
|
event_id = str(uuid.uuid4())
|
|
@@ -62,11 +68,11 @@ class AlertHandler:
|
|
|
62
68
|
update = {"$set": { "resolved_time": event_time}}
|
|
63
69
|
self.mongo.collection.update_one(filter_doc, update)
|
|
64
70
|
alarm_time = self.mongo.collection.find_one(filter_doc, {'event_time': 1})['event_time']
|
|
65
|
-
|
|
71
|
+
|
|
66
72
|
content = [
|
|
67
73
|
f'**事件名称**: {event_name}',
|
|
68
74
|
f'**告警时间**: {TimeUtils.convert_timeobj_to_str(timeobj=event_time, timezone_offset=0) if event_type == "trigger" else TimeUtils.convert_timeobj_to_str(timeobj=alarm_time, timezone_offset=8)}',
|
|
69
|
-
f'**事件内容**: {event_content}',
|
|
75
|
+
f'**事件内容**: {event_content + " 已恢复" if event_type == "resolved" else event_content}',
|
|
70
76
|
f'**告警实例**: {entity_name}',
|
|
71
77
|
f'**建议**: {suggestion}',
|
|
72
78
|
f'**故障排查**: {troubleshot}',
|
|
@@ -78,17 +84,31 @@ class AlertHandler:
|
|
|
78
84
|
|
|
79
85
|
if self.config['feishu']['enable_alert']:
|
|
80
86
|
self.feishu.extensions.send_message_notify(
|
|
87
|
+
receive_id=self.config['feishu']['receive_id'],
|
|
81
88
|
color='red' if event_type == "trigger" else 'green',
|
|
82
|
-
title=event_content,
|
|
89
|
+
title=event_content + " 已恢复" if event_type == "resolved" else event_content,
|
|
83
90
|
priority=priority,
|
|
84
|
-
sub_title=
|
|
91
|
+
sub_title='测试告警, 无需处理' if self.env == 'dev' else '',
|
|
85
92
|
content='\n'.join(content)
|
|
86
93
|
)
|
|
87
94
|
|
|
95
|
+
if self.config['mail']['enable_mail']:
|
|
96
|
+
if event_type == "trigger":
|
|
97
|
+
self.mail.send_mail(
|
|
98
|
+
receiver=[self.config['mail']['mail_address']],
|
|
99
|
+
subject=f"{self.config['mail']['subject_trigger']}, {event_content}",
|
|
100
|
+
contents=f"event_content:{event_content}, alarm_time: {str(event_time)}, event_id: {event_id}, alarm_name: {event_name}, entity_name: {entity_name}, priority: {priority}, automate_ts: {troubleshot}, suggestion: {suggestion}"
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
self.mail.send_mail(
|
|
104
|
+
receiver=[self.config['mail']['mail_address']],
|
|
105
|
+
subject=f"{self.config['mail']['subject_resolved']}, {event_content}",
|
|
106
|
+
contents=f"event_content:{event_content}, alarm_time: {str(TimeUtils.get_now_time_mongo())}, event_id: {event_id}, alarm_name: {event_name}, entity_name: {entity_name}, priority: {priority}, automate_ts: {troubleshot}, suggestion: {suggestion}"
|
|
107
|
+
)
|
|
108
|
+
|
|
88
109
|
if self.config['dida']['enable_alert']:
|
|
89
110
|
if event_type == "trigger":
|
|
90
111
|
res = self.dida.task_create(
|
|
91
|
-
|
|
92
112
|
project_id=self.config['dida']['alert_project_id'],
|
|
93
113
|
title=event_content,
|
|
94
114
|
content='\n'.join(content),
|
|
@@ -8,7 +8,6 @@ from pytbox.feishu.client import Client as FeishuClient
|
|
|
8
8
|
from pytbox.dida365 import Dida365
|
|
9
9
|
from pytbox.alert.alert_handler import AlertHandler
|
|
10
10
|
from pytbox.log.logger import AppLogger
|
|
11
|
-
from pytbox.win.ad import ADClient
|
|
12
11
|
from pytbox.network.meraki import Meraki
|
|
13
12
|
from pytbox.utils.env import get_env_by_os_environment
|
|
14
13
|
from pytbox.vmware import VMwareClient
|
|
@@ -44,6 +43,7 @@ dida = Dida365(
|
|
|
44
43
|
access_token=config['dida']['access_token']
|
|
45
44
|
)
|
|
46
45
|
|
|
46
|
+
|
|
47
47
|
alert_handler = AlertHandler(config=config, mongo_client=get_mongo('alert_test'), feishu_client=feishu, dida_client=dida)
|
|
48
48
|
|
|
49
49
|
def get_logger(app):
|
|
@@ -99,9 +99,9 @@ pyjira = PyJira(
|
|
|
99
99
|
token=config['jira']['token']
|
|
100
100
|
)
|
|
101
101
|
|
|
102
|
-
mail_163 = MailClient(mail_address=config['mail']['163']['mail_address'], password=config['mail']['163']['password'])
|
|
103
|
-
mail_qq = MailClient(mail_address=config['mail']['qq']['mail_address'], password=config['mail']['qq']['password'])
|
|
104
|
-
ali_mail = AliMail(mail_address=config['mail']['aliyun']['mail_address'], client_id=config['mail']['aliyun']['client_id'], client_secret=config['mail']['aliyun']['client_secret'])
|
|
102
|
+
# mail_163 = MailClient(mail_address=config['mail']['163']['mail_address'], password=config['mail']['163']['password'])
|
|
103
|
+
# mail_qq = MailClient(mail_address=config['mail']['qq']['mail_address'], password=config['mail']['qq']['password'])
|
|
104
|
+
# ali_mail = AliMail(mail_address=config['mail']['aliyun']['mail_address'], client_id=config['mail']['aliyun']['client_id'], client_secret=config['mail']['aliyun']['client_secret'])
|
|
105
105
|
|
|
106
106
|
sls = AliCloudSls(
|
|
107
107
|
access_key_id=config['alicloud']['account1']['access_key_id'],
|
|
@@ -110,6 +110,5 @@ sls = AliCloudSls(
|
|
|
110
110
|
logstore=config['alicloud']['account1']['logstore']
|
|
111
111
|
)
|
|
112
112
|
|
|
113
|
-
|
|
114
113
|
def get_cronjob_counter(app_type='', app='', comment=None, schedule_interval=None, schedule_cron=None):
|
|
115
114
|
return cronjob_counter(vm=vm, log=get_logger('cronjob_counter'), app_type=app_type, app=app, comment=comment, schedule_interval=schedule_interval, schedule_cron=schedule_cron)
|
|
@@ -80,7 +80,7 @@ class Mongo:
|
|
|
80
80
|
alarm_list = []
|
|
81
81
|
for result in results:
|
|
82
82
|
duration_minute = '持续 ' + str(int((result['resolved_time'] - result['event_time']).total_seconds() / 60)) + ' 分钟'
|
|
83
|
-
alarm_list.append('
|
|
83
|
+
alarm_list.append('触发时间: ' + TimeUtils.convert_timeobj_to_str(timeobj=result['event_time']) + ' ' + duration_minute)
|
|
84
84
|
|
|
85
85
|
alarm_str = '\n'.join(alarm_list)
|
|
86
86
|
|
|
@@ -230,7 +230,38 @@ class VictoriaMetrics:
|
|
|
230
230
|
rate = r.data[0]['value'][1]
|
|
231
231
|
return int(float(rate))
|
|
232
232
|
|
|
233
|
-
def
|
|
233
|
+
def check_interface_avg_rate(self,
|
|
234
|
+
direction: Literal['in', 'out'],
|
|
235
|
+
sysname: str,
|
|
236
|
+
ifname:str,
|
|
237
|
+
last_hours: Optional[int] = 24,
|
|
238
|
+
last_minutes: Optional[int] = 5,
|
|
239
|
+
) -> ReturnResponse:
|
|
240
|
+
'''
|
|
241
|
+
_summary_
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
direction (Literal['in', 'out']): _description_
|
|
245
|
+
sysname (str): _description_
|
|
246
|
+
ifname (str): _description_
|
|
247
|
+
last_hours (Optional[int], optional): _description_. Defaults to 24.
|
|
248
|
+
last_minutes (Optional[int], optional): _description_. Defaults to 5.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
ReturnResponse: _description_
|
|
252
|
+
'''
|
|
253
|
+
if direction == 'in':
|
|
254
|
+
query = f'avg_over_time(rate(snmp_interface_ifHCInOctets{{sysName="{sysname}", ifName="{ifname}"}}[{last_minutes}m]) * 8 [{last_hours}h:]) / 1e6'
|
|
255
|
+
else:
|
|
256
|
+
query = f'avg_over_time(rate(snmp_interface_ifHCOutOctets{{sysName="{sysname}", ifName="{ifname}"}}[{last_minutes}m]) * 8 [{last_hours}h:]) / 1e6'
|
|
257
|
+
r = self.query(query)
|
|
258
|
+
try:
|
|
259
|
+
rate = r.data[0]['value'][1]
|
|
260
|
+
return ReturnResponse(code=0, msg=f"查询 {sysname} {ifname} 最近 {last_hours} 小时平均速率为 {round(float(rate), 2)} Mbit/s", data=round(float(rate), 2))
|
|
261
|
+
except KeyError:
|
|
262
|
+
return ReturnResponse(code=1, msg=f"查询 {sysname} {ifname} 最近 {last_hours} 小时平均速率为 0 Mbit/s")
|
|
263
|
+
|
|
264
|
+
def check_snmp_port_status(self, sysname: str=None, if_name: str=None, last_minute: int=5, dev_file: str=None) -> ReturnResponse:
|
|
234
265
|
'''
|
|
235
266
|
查询端口状态
|
|
236
267
|
status code 可参考 SNMP 文件 https://mibbrowser.online/mibdb_search.php?mib=IF-MIB
|
|
@@ -245,7 +276,10 @@ class VictoriaMetrics:
|
|
|
245
276
|
code: 0, msg: , data: up,down
|
|
246
277
|
'''
|
|
247
278
|
q = f"""avg_over_time(snmp_interface_ifOperStatus{{sysName="{sysname}", ifName="{if_name}"}}[{last_minute}m])"""
|
|
248
|
-
|
|
279
|
+
if self.env == 'dev':
|
|
280
|
+
r = load_dev_file(dev_file)
|
|
281
|
+
else:
|
|
282
|
+
r = self.query(query=q)
|
|
249
283
|
if r.code == 0:
|
|
250
284
|
status_code = int(r.data[0]['value'][1])
|
|
251
285
|
if status_code == 1:
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from openpyxl.styles import Alignment
|
|
4
|
+
from openpyxl.styles import PatternFill
|
|
5
|
+
from openpyxl.styles.differential import DifferentialStyle
|
|
6
|
+
from openpyxl.styles import Font
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExcelFormat:
|
|
10
|
+
def __init__(self, ws):
|
|
11
|
+
self.ws = ws
|
|
12
|
+
|
|
13
|
+
def set_column(self):
|
|
14
|
+
for column in self.ws.columns:
|
|
15
|
+
max_length = 0
|
|
16
|
+
column = [cell for cell in column]
|
|
17
|
+
for cell in column:
|
|
18
|
+
try:
|
|
19
|
+
if len(str(cell.value)) > max_length:
|
|
20
|
+
max_length = len(cell.value)
|
|
21
|
+
except:
|
|
22
|
+
pass
|
|
23
|
+
adjusted_width = (max_length + 10)
|
|
24
|
+
self.ws.column_dimensions[column[0].column_letter].width = adjusted_width
|
|
25
|
+
|
|
26
|
+
def set_rows_center(self):
|
|
27
|
+
# 将所有单元格的文字居中
|
|
28
|
+
for row in self.ws.iter_rows():
|
|
29
|
+
|
|
30
|
+
for cell in row:
|
|
31
|
+
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
32
|
+
for row in self.ws.iter_rows():
|
|
33
|
+
self.ws.row_dimensions[row[0].row].height = 24
|
|
34
|
+
|
|
35
|
+
def set_freeze_first_row(self):
|
|
36
|
+
"""设置首行锁定/冻结首行"""
|
|
37
|
+
# 冻结首行,从第二行开始滚动
|
|
38
|
+
self.ws.freeze_panes = 'A2'
|
|
39
|
+
|
|
40
|
+
def set_freeze_first_column(self):
|
|
41
|
+
"""设置首列锁定/冻结首列"""
|
|
42
|
+
# 冻结首列,从第二列开始滚动
|
|
43
|
+
self.ws.freeze_panes = 'B1'
|
|
44
|
+
|
|
45
|
+
def set_first_row_bold_color(self, font_color='FF0000FF'):
|
|
46
|
+
"""设置首行字体加粗并改变颜色
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
font_color (str): 字体颜色的十六进制代码,默认为蓝色(FF0000FF)
|
|
50
|
+
格式:AARRGGBB 或 RRGGBB
|
|
51
|
+
例如:'FF0000FF'(蓝色), 'FFFF0000'(红色), 'FF008000'(绿色)
|
|
52
|
+
"""
|
|
53
|
+
# 遍历首行的所有单元格
|
|
54
|
+
for cell in self.ws[1]:
|
|
55
|
+
if cell.value is not None: # 只对有内容的单元格设置样式
|
|
56
|
+
# 设置字体为粗体并改变颜色
|
|
57
|
+
cell.font = Font(bold=True, color=font_color)
|
|
58
|
+
|
|
59
|
+
def set_freeze_first_row_and_column(self):
|
|
60
|
+
"""同时冻结首行和首列"""
|
|
61
|
+
# 冻结首行首列,从第二行第二列开始滚动
|
|
62
|
+
self.ws.freeze_panes = 'B2'
|
|
63
|
+
|
|
64
|
+
|
|
@@ -27,6 +27,10 @@ class MailClient:
|
|
|
27
27
|
elif 'foxmail.com' in mail_address:
|
|
28
28
|
self.smtp_address = 'smtp.qq.com'
|
|
29
29
|
self.imap_address = 'imap.qq.com'
|
|
30
|
+
|
|
31
|
+
elif 'mail' in mail_address and 'cn' in mail_address:
|
|
32
|
+
self.smtp_address = "smtpdm.aliyun.com"
|
|
33
|
+
self.imap_address = ""
|
|
30
34
|
|
|
31
35
|
else:
|
|
32
36
|
raise ValueError(f'不支持的邮箱地址: {mail_address}')
|
|
@@ -21,8 +21,14 @@ def test_check_snmp_port_status():
|
|
|
21
21
|
r = vm.check_snmp_port_status(sysname="shylf-prod-coresw-ce6820-182", if_name="10GE1/0/47", last_minute=10)
|
|
22
22
|
print(r)
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
r = vm.check_interface_avg_rate(direction='in', sysname='whcq-prod-coresw-s6720-254', ifname='XGigabitEthernet0/0/47', last_hours=24, last_minutes=5)
|
|
26
|
+
print(r)
|
|
27
|
+
|
|
24
28
|
if __name__ == "__main__":
|
|
25
29
|
# test_get_labels()
|
|
26
30
|
# test_query()
|
|
27
31
|
# test_check_ping_result()
|
|
28
|
-
test_check_snmp_port_status()
|
|
32
|
+
# test_check_snmp_port_status()
|
|
33
|
+
# test_check_interface_avg_rate()
|
|
34
|
+
pass
|
pytbox-0.1.8/src/pytbox/excel.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.http_response/http_response.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.net_response/net_response.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
{pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
{pytbox-0.1.8 → pytbox-0.2.0}/src/pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|