pytbox 0.0.7__py3-none-any.whl → 0.3.1__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.
Potentially problematic release.
This version of pytbox might be problematic. Click here for more details.
- pytbox/alert/alert_handler.py +27 -7
- pytbox/alert/ping.py +0 -1
- pytbox/alicloud/sls.py +9 -6
- pytbox/base.py +74 -1
- pytbox/categraf/build_config.py +95 -32
- pytbox/categraf/instances.toml +39 -0
- pytbox/categraf/jinja2/__init__.py +6 -0
- pytbox/categraf/jinja2/input.cpu/cpu.toml.j2 +5 -0
- pytbox/categraf/jinja2/input.disk/disk.toml.j2 +11 -0
- pytbox/categraf/jinja2/input.diskio/diskio.toml.j2 +6 -0
- pytbox/categraf/jinja2/input.dns_query/dns_query.toml.j2 +12 -0
- pytbox/categraf/jinja2/input.http_response/http_response.toml.j2 +9 -0
- pytbox/categraf/jinja2/input.mem/mem.toml.j2 +5 -0
- pytbox/categraf/jinja2/input.net/net.toml.j2 +11 -0
- pytbox/categraf/jinja2/input.net_response/net_response.toml.j2 +9 -0
- pytbox/categraf/jinja2/input.ping/ping.toml.j2 +11 -0
- pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2 +12 -0
- pytbox/categraf/jinja2/input.snmp/cisco_interface.toml.j2 +96 -0
- pytbox/categraf/jinja2/input.snmp/cisco_system.toml.j2 +41 -0
- pytbox/categraf/jinja2/input.snmp/h3c_interface.toml.j2 +96 -0
- pytbox/categraf/jinja2/input.snmp/h3c_system.toml.j2 +41 -0
- pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2 +96 -0
- pytbox/categraf/jinja2/input.snmp/huawei_system.toml.j2 +41 -0
- pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2 +96 -0
- pytbox/categraf/jinja2/input.snmp/ruijie_system.toml.j2 +41 -0
- pytbox/categraf/jinja2/input.vsphere/vsphere.toml.j2 +211 -0
- pytbox/cli/commands/vm.py +22 -0
- pytbox/cli/main.py +2 -0
- pytbox/database/mongo.py +1 -1
- pytbox/database/victoriametrics.py +331 -40
- pytbox/excel.py +64 -0
- pytbox/feishu/endpoints.py +6 -6
- pytbox/log/logger.py +29 -12
- pytbox/mail/alimail.py +142 -0
- pytbox/mail/client.py +171 -0
- pytbox/mail/mail_detail.py +30 -0
- pytbox/mingdao.py +164 -0
- pytbox/network/meraki.py +537 -0
- pytbox/notion.py +731 -0
- pytbox/pyjira.py +612 -0
- pytbox/utils/cronjob.py +79 -0
- pytbox/utils/env.py +2 -2
- pytbox/utils/load_config.py +67 -21
- pytbox/utils/load_vm_devfile.py +45 -0
- pytbox/utils/richutils.py +11 -1
- pytbox/utils/timeutils.py +15 -57
- pytbox/vmware.py +120 -0
- pytbox/win/ad.py +30 -0
- {pytbox-0.0.7.dist-info → pytbox-0.3.1.dist-info}/METADATA +7 -4
- pytbox-0.3.1.dist-info/RECORD +72 -0
- pytbox/utils/ping_checker.py +0 -1
- pytbox-0.0.7.dist-info/RECORD +0 -39
- {pytbox-0.0.7.dist-info → pytbox-0.3.1.dist-info}/WHEEL +0 -0
- {pytbox-0.0.7.dist-info → pytbox-0.3.1.dist-info}/entry_points.txt +0 -0
- {pytbox-0.0.7.dist-info → pytbox-0.3.1.dist-info}/top_level.txt +0 -0
pytbox/utils/env.py
CHANGED
|
@@ -17,14 +17,14 @@ def get_env_by_file_exist(file_path: str) -> Literal['prod', 'dev']:
|
|
|
17
17
|
return 'dev'
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
def get_env_by_os_environment() -> Literal['dev', 'prod']:
|
|
20
|
+
def get_env_by_os_environment(check_key: str='ENV') -> Literal['dev', 'prod']:
|
|
21
21
|
'''
|
|
22
22
|
根据环境变量获取环境
|
|
23
23
|
|
|
24
24
|
Returns:
|
|
25
25
|
Literal['dev', 'prod']: 环境,dev 表示开发环境,prod 表示生产环境
|
|
26
26
|
'''
|
|
27
|
-
if os.getenv(
|
|
27
|
+
if os.getenv(check_key) == 'dev':
|
|
28
28
|
return 'dev'
|
|
29
29
|
else:
|
|
30
30
|
return 'prod'
|
pytbox/utils/load_config.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
3
5
|
|
|
4
6
|
try:
|
|
5
7
|
import toml
|
|
@@ -8,13 +10,14 @@ except ImportError:
|
|
|
8
10
|
from pytbox.onepassword_connect import OnePasswordConnect
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def
|
|
13
|
+
def _replace_values(data, oc=None, jsonfile_path=None):
|
|
12
14
|
"""
|
|
13
|
-
递归处理配置数据,替换 1password 和
|
|
15
|
+
递归处理配置数据,替换 1password、password 和 jsonfile 开头的值
|
|
14
16
|
|
|
15
17
|
Args:
|
|
16
18
|
data: 配置数据(dict, list, str 等)
|
|
17
19
|
oc: OnePasswordConnect 实例
|
|
20
|
+
jsonfile_path: JSON 文件路径
|
|
18
21
|
|
|
19
22
|
Returns:
|
|
20
23
|
处理后的数据
|
|
@@ -22,41 +25,81 @@ def _replace_1password_values(data, oc):
|
|
|
22
25
|
if isinstance(data, dict):
|
|
23
26
|
result = {}
|
|
24
27
|
for k, v in data.items():
|
|
25
|
-
result[k] =
|
|
28
|
+
result[k] = _replace_values(v, oc, jsonfile_path)
|
|
26
29
|
return result
|
|
27
30
|
elif isinstance(data, list):
|
|
28
|
-
return [
|
|
31
|
+
return [_replace_values(item, oc, jsonfile_path) for item in data]
|
|
29
32
|
elif isinstance(data, str):
|
|
30
33
|
# 处理 1password,item_id,field_name 格式
|
|
31
|
-
if data.startswith("1password,"):
|
|
34
|
+
if data.startswith("1password,") and oc:
|
|
32
35
|
parts = data.split(",")
|
|
33
36
|
if len(parts) >= 3:
|
|
34
37
|
item_id = parts[1]
|
|
35
38
|
field_name = parts[2]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
try:
|
|
40
|
+
# 通过 item_id 获取项目,然后从字段中提取对应值
|
|
41
|
+
item = oc.get_item(item_id)
|
|
42
|
+
for field in item.fields:
|
|
43
|
+
if field.label == field_name:
|
|
44
|
+
return field.value
|
|
45
|
+
except (AttributeError, KeyError, ValueError):
|
|
46
|
+
pass
|
|
41
47
|
return data # 如果找不到字段,返回原始值
|
|
42
48
|
# 处理 password,item_id,field_name 格式
|
|
43
|
-
elif data.startswith("password,"):
|
|
49
|
+
elif data.startswith("password,") and oc:
|
|
44
50
|
parts = data.split(",")
|
|
45
51
|
if len(parts) >= 3:
|
|
46
52
|
item_id = parts[1]
|
|
47
53
|
field_name = parts[2]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
try:
|
|
55
|
+
# 通过 item_id 获取项目,然后从字段中提取对应值
|
|
56
|
+
item = oc.get_item(item_id)
|
|
57
|
+
for field in item.fields:
|
|
58
|
+
if field.label == field_name:
|
|
59
|
+
return field.value
|
|
60
|
+
except (AttributeError, KeyError, ValueError):
|
|
61
|
+
pass
|
|
53
62
|
return data # 如果找不到字段,返回原始值
|
|
63
|
+
# 处理 jsonfile,key 格式
|
|
64
|
+
elif data.startswith("jsonfile,"):
|
|
65
|
+
parts = data.split(",", 1) # 只分割一次,防止 key 中包含逗号
|
|
66
|
+
if len(parts) >= 2:
|
|
67
|
+
key = parts[1]
|
|
68
|
+
|
|
69
|
+
# 尝试从 JSON 文件获取值
|
|
70
|
+
if jsonfile_path and os.path.exists(jsonfile_path):
|
|
71
|
+
try:
|
|
72
|
+
with open(jsonfile_path, 'r', encoding='utf-8') as f:
|
|
73
|
+
json_data = json.load(f)
|
|
74
|
+
# 支持嵌套键,如 "db.password"
|
|
75
|
+
value = json_data
|
|
76
|
+
for k in key.split('.'):
|
|
77
|
+
if isinstance(value, dict) and k in value:
|
|
78
|
+
value = value[k]
|
|
79
|
+
else:
|
|
80
|
+
value = None
|
|
81
|
+
break
|
|
82
|
+
if value is not None:
|
|
83
|
+
return value
|
|
84
|
+
except (json.JSONDecodeError, FileNotFoundError, KeyError):
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
# 如果从 JSON 文件获取失败,尝试从环境变量获取
|
|
88
|
+
env_value = os.getenv(key)
|
|
89
|
+
if env_value is not None:
|
|
90
|
+
return env_value
|
|
91
|
+
|
|
92
|
+
return data # 如果都获取不到,返回原始值
|
|
54
93
|
return data
|
|
55
94
|
else:
|
|
56
95
|
return data
|
|
57
96
|
|
|
58
97
|
|
|
59
|
-
def load_config_by_file(
|
|
98
|
+
def load_config_by_file(
|
|
99
|
+
path: str='/workspaces/pytbox/src/pytbox/alert/config/config.toml',
|
|
100
|
+
oc_vault_id: str=None,
|
|
101
|
+
jsonfile: str="/data/jsonfile.json",
|
|
102
|
+
) -> dict:
|
|
60
103
|
'''
|
|
61
104
|
从文件加载配置,支持 1password 集成
|
|
62
105
|
|
|
@@ -68,17 +111,20 @@ def load_config_by_file(path: str='/workspaces/pytbox/src/pytbox/alert/config/co
|
|
|
68
111
|
dict: 配置字典
|
|
69
112
|
'''
|
|
70
113
|
with open(path, 'r', encoding='utf-8') as f:
|
|
71
|
-
if path.endswith('.toml'):
|
|
114
|
+
if path.endswith('.toml'):
|
|
72
115
|
config = toml.load(f)
|
|
73
116
|
else:
|
|
74
117
|
# 如果不是 toml 文件,假设是其他格式,这里可以扩展
|
|
75
|
-
import json
|
|
76
118
|
config = json.load(f)
|
|
77
119
|
|
|
120
|
+
# 处理配置值替换
|
|
121
|
+
oc = None
|
|
78
122
|
if oc_vault_id:
|
|
79
123
|
oc = OnePasswordConnect(vault_id=oc_vault_id)
|
|
80
|
-
|
|
81
|
-
|
|
124
|
+
|
|
125
|
+
# 替换配置中的特殊值(1password, password, jsonfile)
|
|
126
|
+
config = _replace_values(config, oc, jsonfile)
|
|
127
|
+
|
|
82
128
|
return config
|
|
83
129
|
|
|
84
130
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pytbox.utils.response import ReturnResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def load_dev_file(file_path: str) -> ReturnResponse:
|
|
8
|
+
"""从开发环境文件加载数据并返回 ReturnResponse 对象
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
file_path: JSON 文件路径
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
ReturnResponse: 包装后的响应对象
|
|
15
|
+
"""
|
|
16
|
+
try:
|
|
17
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
18
|
+
data = json.load(f)
|
|
19
|
+
|
|
20
|
+
# 如果已经是 ReturnResponse 格式的字典,直接转换
|
|
21
|
+
if isinstance(data, dict) and 'code' in data and 'msg' in data:
|
|
22
|
+
return ReturnResponse(
|
|
23
|
+
code=data.get('code', 0),
|
|
24
|
+
msg=data.get('msg', ''),
|
|
25
|
+
data=data.get('data', None)
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
# 如果是其他格式,包装成成功响应
|
|
29
|
+
return ReturnResponse(
|
|
30
|
+
code=0,
|
|
31
|
+
msg='开发文件加载成功',
|
|
32
|
+
data=data
|
|
33
|
+
)
|
|
34
|
+
except FileNotFoundError:
|
|
35
|
+
return ReturnResponse(
|
|
36
|
+
code=4,
|
|
37
|
+
msg=f'开发文件未找到: {file_path}',
|
|
38
|
+
data=None
|
|
39
|
+
)
|
|
40
|
+
except json.JSONDecodeError as e:
|
|
41
|
+
return ReturnResponse(
|
|
42
|
+
code=1,
|
|
43
|
+
msg=f'JSON 解析错误: {str(e)}',
|
|
44
|
+
data=None
|
|
45
|
+
)
|
pytbox/utils/richutils.py
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from typing import Literal
|
|
5
5
|
from rich.console import Console
|
|
6
6
|
from rich.theme import Theme
|
|
7
|
+
from rich.prompt import Prompt
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class RichUtils:
|
|
@@ -18,4 +19,13 @@ class RichUtils:
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def print(self, msg: str, style: Literal['info', 'warning', 'danger']='info'):
|
|
21
|
-
self.console.print(msg, style=style)
|
|
22
|
+
self.console.print(msg, style=style)
|
|
23
|
+
|
|
24
|
+
def ask(self, msg: str="是否继续操作?", choices: list[str]=["Y", "N", "CANCEL"], default: str='N', show_choices: bool=True):
|
|
25
|
+
choice = Prompt.ask(
|
|
26
|
+
f"[bold cyan]{msg}[/bold cyan]",
|
|
27
|
+
choices=choices,
|
|
28
|
+
default=default,
|
|
29
|
+
show_choices=show_choices,
|
|
30
|
+
)
|
|
31
|
+
return choice
|
pytbox/utils/timeutils.py
CHANGED
|
@@ -120,24 +120,6 @@ class TimeUtils:
|
|
|
120
120
|
dt = datetime.datetime.strptime(timestr_fixed, "%Y-%m-%dT%H:%M:%S%z")
|
|
121
121
|
# 返回秒级时间戳
|
|
122
122
|
return int(dt.timestamp()) * 1000
|
|
123
|
-
|
|
124
|
-
@staticmethod
|
|
125
|
-
def convert_str_to_datetime_lg_backup(time_str: str):
|
|
126
|
-
"""
|
|
127
|
-
将 '7/10/2025 3:52:43 PM' 这种格式的时间字符串转换为时间戳(秒级)。
|
|
128
|
-
|
|
129
|
-
Args:
|
|
130
|
-
time_str (str): 时间字符串,格式如 '7/10/2025 3:52:43 PM'
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
int: 时间戳(秒级)
|
|
134
|
-
"""
|
|
135
|
-
if time_str is None:
|
|
136
|
-
return None
|
|
137
|
-
# 先将字符串转换为 datetime 对象
|
|
138
|
-
dt = datetime.datetime.strptime(time_str, "%m/%d/%Y %I:%M:%S %p")
|
|
139
|
-
# 返回秒级时间戳
|
|
140
|
-
return int(dt.timestamp()) * 1000
|
|
141
123
|
|
|
142
124
|
@staticmethod
|
|
143
125
|
def convert_timestamp_to_str(timestamp: int, time_format: Literal['%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%dT%H:%M:%S.000Z']='%Y-%m-%d %H:%M:%S', timezone_offset: int=8):
|
|
@@ -286,29 +268,6 @@ class TimeUtils:
|
|
|
286
268
|
def get_today_timestamp() -> int:
|
|
287
269
|
return int(time.time()) * 1000
|
|
288
270
|
|
|
289
|
-
@staticmethod
|
|
290
|
-
def convert_str_to_datetime(time_str: str, app: Literal['lg_alert_trigger', 'lg_alert_resolved', 'mongo']='lg_alert_trigger') -> datetime.datetime:
|
|
291
|
-
"""
|
|
292
|
-
将字符串转换为datetime对象
|
|
293
|
-
|
|
294
|
-
Args:
|
|
295
|
-
time_str (str): 时间字符串
|
|
296
|
-
app (Literal['lg_alert_trigger', 'lg_alert_resolved', 'mongo'], optional): 应用类型. Defaults to 'lg_alert_trigger'.
|
|
297
|
-
|
|
298
|
-
Returns:
|
|
299
|
-
datetime.datetime: 带时区信息的datetime对象
|
|
300
|
-
"""
|
|
301
|
-
if app == 'lg_alert_trigger':
|
|
302
|
-
time_obj = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
|
|
303
|
-
elif app == 'lg_alert_resolved':
|
|
304
|
-
time_obj = datetime.datetime.strptime(time_str, "%Y年%m月%d日 %H:%M:%S")
|
|
305
|
-
elif app == 'mongo':
|
|
306
|
-
time_obj = datetime.datetime.fromisoformat(time_str.replace('Z', '+00:00'))
|
|
307
|
-
return time_obj # 已经包含时区信息,直接返回
|
|
308
|
-
|
|
309
|
-
# 对于没有时区信息的时间对象,设置为Asia/Shanghai时区
|
|
310
|
-
time_with_tz = time_obj.replace(tzinfo=ZoneInfo("Asia/Shanghai"))
|
|
311
|
-
return time_with_tz
|
|
312
271
|
|
|
313
272
|
@staticmethod
|
|
314
273
|
def convert_timeobj_to_str(timeobj: str=None, timezone_offset: int=8, time_format: Literal['%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%SZ']='%Y-%m-%d %H:%M:%S'):
|
|
@@ -511,21 +470,6 @@ class TimeUtils:
|
|
|
511
470
|
# weekday()方法返回0-6的数字,0表示周一,6表示周日
|
|
512
471
|
return now.weekday() + 1 + offset
|
|
513
472
|
|
|
514
|
-
@staticmethod
|
|
515
|
-
def get_week_of_year(customer: Literal['lululemon', 'other']='other') -> tuple[int, int]:
|
|
516
|
-
'''
|
|
517
|
-
获取今天是哪一年的第几周
|
|
518
|
-
|
|
519
|
-
Returns:
|
|
520
|
-
tuple[int, int]: 返回一个元组,包含(年份, 周数)
|
|
521
|
-
'''
|
|
522
|
-
now = datetime.datetime.now()
|
|
523
|
-
# isocalendar()方法返回一个元组,包含年份、周数和周几
|
|
524
|
-
_year, week, _ = now.isocalendar()
|
|
525
|
-
if customer == 'lululemon':
|
|
526
|
-
week = week - 5
|
|
527
|
-
return _year, week
|
|
528
|
-
|
|
529
473
|
@staticmethod
|
|
530
474
|
def get_last_month_start_and_end_time() -> tuple[datetime.datetime, datetime.datetime]:
|
|
531
475
|
'''
|
|
@@ -544,4 +488,18 @@ class TimeUtils:
|
|
|
544
488
|
# 获取上个月的最后一天
|
|
545
489
|
end_time = first_day_of_current_month - datetime.timedelta(days=1)
|
|
546
490
|
end_time = end_time.replace(hour=23, minute=59, second=59, microsecond=0)
|
|
547
|
-
return start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
491
|
+
return start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
492
|
+
|
|
493
|
+
@staticmethod
|
|
494
|
+
def convert_rfc3339_to_unix_ms(ts_str: str) -> int:
|
|
495
|
+
"""
|
|
496
|
+
将 RFC3339 格式的时间字符串转换为毫秒级时间戳
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
ts_str (str): RFC3339 格式的时间字符串
|
|
500
|
+
|
|
501
|
+
Returns:
|
|
502
|
+
int: 毫秒级时间戳
|
|
503
|
+
"""
|
|
504
|
+
dt = datetime.datetime.fromisoformat(ts_str.replace("Z", "+00:00"))
|
|
505
|
+
return int(dt.timestamp() * 1000)
|
pytbox/vmware.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from typing import Any, Dict, Optional, Union, Literal
|
|
5
|
+
import urllib3
|
|
6
|
+
urllib3.disable_warnings()
|
|
7
|
+
import requests
|
|
8
|
+
from requests.auth import HTTPBasicAuth
|
|
9
|
+
|
|
10
|
+
from .utils.response import ReturnResponse
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VMwareClient:
|
|
14
|
+
"""VMware vSphere Automation API 客户端。
|
|
15
|
+
|
|
16
|
+
支持多种认证方式:
|
|
17
|
+
1. Basic Auth - HTTP 基础认证
|
|
18
|
+
2. API Key Auth - 使用会话 ID 认证
|
|
19
|
+
3. Federated Identity Auth - 联合身份认证(Bearer Token)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
host: str=None,
|
|
25
|
+
username: str=None,
|
|
26
|
+
password: str=None,
|
|
27
|
+
version: Literal['6.7', '7.0']='6.7',
|
|
28
|
+
proxies: dict=None,
|
|
29
|
+
verify_ssl: bool = False,
|
|
30
|
+
timeout: int = 30,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""初始化 VMware 客户端。
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
host: vCenter Server 主机地址(例如:https://vcenter.example.com)
|
|
36
|
+
verify_ssl: 是否验证 SSL 证书
|
|
37
|
+
timeout: 请求超时时间(秒)
|
|
38
|
+
proxy_host: 代理服务器主机地址
|
|
39
|
+
proxy_port: 代理服务器端口
|
|
40
|
+
proxy_username: 代理认证用户名(可选)
|
|
41
|
+
proxy_password: 代理认证密码(可选)
|
|
42
|
+
"""
|
|
43
|
+
self.host = host
|
|
44
|
+
self.username = username
|
|
45
|
+
self.password = password
|
|
46
|
+
self.version = version
|
|
47
|
+
self.proxies = proxies
|
|
48
|
+
self.verify_ssl = verify_ssl
|
|
49
|
+
self.timeout = timeout
|
|
50
|
+
self.session_id: Optional[str] = None
|
|
51
|
+
|
|
52
|
+
self.headers = {
|
|
53
|
+
"vmware-api-session-id": self.get_session()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
def get_session(self) -> str:
|
|
57
|
+
"""获取 VMware vSphere API 会话 ID。
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
会话 ID 字符串
|
|
61
|
+
"""
|
|
62
|
+
if self.version == '6.7':
|
|
63
|
+
url = f"{self.host}/rest/com/vmware/cis/session"
|
|
64
|
+
else:
|
|
65
|
+
url = f"{self.host}/api/session"
|
|
66
|
+
|
|
67
|
+
response = requests.post(
|
|
68
|
+
url,
|
|
69
|
+
auth=HTTPBasicAuth(self.username, self.password),
|
|
70
|
+
timeout=self.timeout,
|
|
71
|
+
verify=self.verify_ssl,
|
|
72
|
+
proxies=self.proxies
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if response.status_code == 200 or response.status_code == 201:
|
|
76
|
+
# vSphere API 通常直接返回 session ID 字符串
|
|
77
|
+
session_id = response.json()
|
|
78
|
+
try:
|
|
79
|
+
return session_id['value']
|
|
80
|
+
except Exception:
|
|
81
|
+
return session_id
|
|
82
|
+
else:
|
|
83
|
+
return f"认证失败: {response.status_code} - {response.text}"
|
|
84
|
+
|
|
85
|
+
def get_vm_list(self) -> ReturnResponse:
|
|
86
|
+
'''
|
|
87
|
+
_summary_
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
ReturnResponse: _description_
|
|
91
|
+
'''
|
|
92
|
+
if self.version == '6.7':
|
|
93
|
+
url = f"{self.host}/rest/vcenter/vm"
|
|
94
|
+
else:
|
|
95
|
+
url = f"{self.host}/api/vcenter/vm"
|
|
96
|
+
response = requests.get(url, headers=self.headers, timeout=self.timeout, verify=False, proxies=self.proxies)
|
|
97
|
+
if response.status_code == 200:
|
|
98
|
+
if self.version == '6.7':
|
|
99
|
+
data = response.json().get('value')
|
|
100
|
+
else:
|
|
101
|
+
data = response.json()
|
|
102
|
+
return ReturnResponse(code=0, msg=f'成功获取到 {len(data)} 台虚拟机', data=data)
|
|
103
|
+
else:
|
|
104
|
+
return ReturnResponse(code=1, msg='error', data=response.json())
|
|
105
|
+
|
|
106
|
+
def get_vm(self, vm_id):
|
|
107
|
+
if self.version == '6.7':
|
|
108
|
+
url = f"{self.host}/rest/vcenter/vm/{vm_id}"
|
|
109
|
+
else:
|
|
110
|
+
url = f"{self.host}/api/vcenter/vm/{vm_id}"
|
|
111
|
+
response = requests.get(url, headers=self.headers, timeout=self.timeout, verify=False, proxies=self.proxies)
|
|
112
|
+
if response.status_code == 200:
|
|
113
|
+
return ReturnResponse(code=0, msg='成功获取到虚拟机', data=response.json())
|
|
114
|
+
else:
|
|
115
|
+
return ReturnResponse(code=1, msg=f"{response.status_code}, {response.text}", data=response.json())
|
|
116
|
+
|
|
117
|
+
# 使用示例
|
|
118
|
+
if __name__ == "__main__":
|
|
119
|
+
pass
|
|
120
|
+
|
pytbox/win/ad.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from ldap3 import Server, Connection, ALL, SUBTREE, MODIFY_REPLACE, SUBTREE, MODIFY_ADD, MODIFY_DELETE
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ADClient:
|
|
8
|
+
'''
|
|
9
|
+
_summary_
|
|
10
|
+
'''
|
|
11
|
+
def __init__(self, server, base_dn, username, password):
|
|
12
|
+
self.server = Server(server, get_info=ALL)
|
|
13
|
+
self.conn = Connection(self.server, user=username, password=password, auto_bind=True)
|
|
14
|
+
self.base_dn = base_dn
|
|
15
|
+
|
|
16
|
+
def list_user(self):
|
|
17
|
+
'''
|
|
18
|
+
查询所有用户
|
|
19
|
+
|
|
20
|
+
Yields:
|
|
21
|
+
dict: 返回的是生成器, 字典类型
|
|
22
|
+
'''
|
|
23
|
+
# 搜索过滤条件
|
|
24
|
+
secarch_filter = '(objectCategory=person)' # 过滤所有用户
|
|
25
|
+
# SEARCH_ATTRIBUTES = ['cn', 'sAMAccountName', 'mail', 'userPrincipalName'] # 需要的用户属性
|
|
26
|
+
search_attributes = ["*"] # 需要的用户属性
|
|
27
|
+
# 搜索用户
|
|
28
|
+
if self.conn.search(search_base=self.base_dn, search_filter=secarch_filter, search_scope=SUBTREE, attributes=search_attributes):
|
|
29
|
+
for entry in self.conn.entries:
|
|
30
|
+
yield {k: v[0] if isinstance(v, list) else v for k, v in entry.entry_attributes_as_dict.items()}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytbox
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: A collection of Python integrations and utilities (Feishu, Dida365, VictoriaMetrics, ...)
|
|
5
5
|
Author-email: mingming hou <houm01@foxmail.com>
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Requires-Python: >=3.8
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
9
|
Requires-Dist: requests>=2.0
|
|
@@ -13,15 +13,18 @@ Requires-Dist: loguru>=0.7.3
|
|
|
13
13
|
Requires-Dist: chinese_calendar>=1.10.0
|
|
14
14
|
Requires-Dist: click>=8.0.0
|
|
15
15
|
Requires-Dist: rich>=12.0.0
|
|
16
|
+
Requires-Dist: jinja2>=3.0.0
|
|
17
|
+
Requires-Dist: toml>=0.10.0
|
|
18
|
+
Requires-Dist: ldap3>=2.9.1
|
|
19
|
+
Requires-Dist: imap-tools>=1.11.0
|
|
20
|
+
Requires-Dist: yagmail>=0.15.293
|
|
16
21
|
Provides-Extra: dev
|
|
17
22
|
Requires-Dist: pytest; extra == "dev"
|
|
18
23
|
Requires-Dist: black; extra == "dev"
|
|
19
24
|
Requires-Dist: ruff; extra == "dev"
|
|
20
25
|
Requires-Dist: python-dotenv; extra == "dev"
|
|
21
26
|
Provides-Extra: cli
|
|
22
|
-
Requires-Dist: jinja2>=3.0.0; extra == "cli"
|
|
23
27
|
Requires-Dist: pyyaml>=6.0; extra == "cli"
|
|
24
|
-
Requires-Dist: toml>=0.10.0; extra == "cli"
|
|
25
28
|
|
|
26
29
|
# PytBox
|
|
27
30
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
pytbox/base.py,sha256=WC_p_PYMMpNq-5JRLyZoD74k-d2EQVmO4VjTvnI7VqE,4541
|
|
2
|
+
pytbox/cli.py,sha256=N775a0GK80IT2lQC2KRYtkZpIiu9UjavZmaxgNUgJhQ,160
|
|
3
|
+
pytbox/dida365.py,sha256=pUMPB9AyLZpTTbaz2LbtzdEpyjvuGf4YlRrCvM5sbJo,10545
|
|
4
|
+
pytbox/excel.py,sha256=f5XBLCeJbGgxytoSwVhbk03WLTzz8Q3IJ_RZ2-r_w6A,2334
|
|
5
|
+
pytbox/mingdao.py,sha256=afEFJ9NKPdsmAZ4trBEJKl66fMj3Z8TWfaOcomNGhzw,6042
|
|
6
|
+
pytbox/notion.py,sha256=GRPdZAtyG2I6M6pCFbdrTWDACaPsp1RAXrY_RpWYKus,26572
|
|
7
|
+
pytbox/onepassword_connect.py,sha256=nD3xTl1ykQ4ct_dCRRF138gXCtk-phPfKYXuOn-P7Z8,3064
|
|
8
|
+
pytbox/onepassword_sa.py,sha256=08iUcYud3aEHuQcUsem9bWNxdXKgaxFbMy9yvtr-DZQ,6995
|
|
9
|
+
pytbox/pyjira.py,sha256=Str9f7qTeBuy8XtJq2bXBI9ib79aQYCHBlJP1QKtZeo,24605
|
|
10
|
+
pytbox/vmware.py,sha256=WiH67_3-VCBjXJuh3UueOc31BdZDItiZhkeuPzoRhw4,3975
|
|
11
|
+
pytbox/alert/alert_handler.py,sha256=WCn4cKahv5G5BFGgmc7dX7BQ38h2kxTgxfRVTwc1O2M,6579
|
|
12
|
+
pytbox/alert/ping.py,sha256=KEnnXdIRJHvR_rEHPWLBt0wz4cGwmA29Lenlak3Z_1Y,778
|
|
13
|
+
pytbox/alicloud/sls.py,sha256=-r6rbCwDUQ4jwAgSVSNu7B2h1MNg20CrRIKnlXVeY9w,4159
|
|
14
|
+
pytbox/categraf/build_config.py,sha256=9G85rLqkz3lchpH7ef0LbvckYHl0nRA6mHVLeUfs9Mw,6308
|
|
15
|
+
pytbox/categraf/instances.toml,sha256=jcJyEaqhohUcECczWArxUK4t0-rdk4vmrX21kxZlSLA,1254
|
|
16
|
+
pytbox/categraf/jinja2/__init__.py,sha256=Epm01j8Oujeg4Sk5GgHMvgKIZ6h3BTx-MGmuMgIjUMo,150
|
|
17
|
+
pytbox/categraf/jinja2/input.cpu/cpu.toml.j2,sha256=wxpyLDNvz2ViZK-0a4EgH35Zsg82CwMwijOtT0nBfTI,92
|
|
18
|
+
pytbox/categraf/jinja2/input.disk/disk.toml.j2,sha256=kOWwVF6u7x2huLVa4eBIOhC8R13DXmw0PD9o3HXwEZo,420
|
|
19
|
+
pytbox/categraf/jinja2/input.diskio/diskio.toml.j2,sha256=33E4L1mkUkJOocUsSgpW5zoFCzvx5ogfbnm2jkwzLx8,227
|
|
20
|
+
pytbox/categraf/jinja2/input.dns_query/dns_query.toml.j2,sha256=-oMkIMtCg4zq_oGENrm9aUzUzVkWmgxPSrGlwo2k2Pc,461
|
|
21
|
+
pytbox/categraf/jinja2/input.http_response/http_response.toml.j2,sha256=Qp1EOxx7TC7_cH69KqMVwbfCKrD5xbbVO2drVdkvo6s,317
|
|
22
|
+
pytbox/categraf/jinja2/input.mem/mem.toml.j2,sha256=_-qJyE0K_76IMehbN1xq1hi9vY1Y1Jp4TuITzaLjCg4,116
|
|
23
|
+
pytbox/categraf/jinja2/input.net/net.toml.j2,sha256=yodVoT1f7bcuNMFFmAvc7WhORUsTnM92IhpWQHXfY_U,279
|
|
24
|
+
pytbox/categraf/jinja2/input.net_response/net_response.toml.j2,sha256=Qp1EOxx7TC7_cH69KqMVwbfCKrD5xbbVO2drVdkvo6s,317
|
|
25
|
+
pytbox/categraf/jinja2/input.ping/ping.toml.j2,sha256=UCRy_IVoI_FDQxfsDpGS-aZJasFG1sf67ScN9U8YVIo,344
|
|
26
|
+
pytbox/categraf/jinja2/input.prometheus/prometheus.toml.j2,sha256=6ax30L1sAUreojlzf0v26GzOAiheCP0Lj7n5IIjgco0,384
|
|
27
|
+
pytbox/categraf/jinja2/input.snmp/cisco_interface.toml.j2,sha256=0u7eEoi4Q_NB8nnujq8a424r7GNB1eR8J3DToOhwWeQ,1941
|
|
28
|
+
pytbox/categraf/jinja2/input.snmp/cisco_system.toml.j2,sha256=DMJSEouhyGu54BIxehzsHQnnMgPHjnTweuVG0Y5iIw4,925
|
|
29
|
+
pytbox/categraf/jinja2/input.snmp/h3c_interface.toml.j2,sha256=0u7eEoi4Q_NB8nnujq8a424r7GNB1eR8J3DToOhwWeQ,1941
|
|
30
|
+
pytbox/categraf/jinja2/input.snmp/h3c_system.toml.j2,sha256=DMJSEouhyGu54BIxehzsHQnnMgPHjnTweuVG0Y5iIw4,925
|
|
31
|
+
pytbox/categraf/jinja2/input.snmp/huawei_interface.toml.j2,sha256=0u7eEoi4Q_NB8nnujq8a424r7GNB1eR8J3DToOhwWeQ,1941
|
|
32
|
+
pytbox/categraf/jinja2/input.snmp/huawei_system.toml.j2,sha256=DMJSEouhyGu54BIxehzsHQnnMgPHjnTweuVG0Y5iIw4,925
|
|
33
|
+
pytbox/categraf/jinja2/input.snmp/ruijie_interface.toml.j2,sha256=0u7eEoi4Q_NB8nnujq8a424r7GNB1eR8J3DToOhwWeQ,1941
|
|
34
|
+
pytbox/categraf/jinja2/input.snmp/ruijie_system.toml.j2,sha256=DMJSEouhyGu54BIxehzsHQnnMgPHjnTweuVG0Y5iIw4,925
|
|
35
|
+
pytbox/categraf/jinja2/input.vsphere/vsphere.toml.j2,sha256=7SCo8DSh5Uuy-7MeWw-soy6sqblK54k6K2WWSlimELk,8396
|
|
36
|
+
pytbox/cli/__init__.py,sha256=5ID4-oXrMsHFcfDsQeXDYeThPOuQ1Fl2x2kHWfgfOEw,67
|
|
37
|
+
pytbox/cli/main.py,sha256=CywsgiwQepM-mTGTnmDLcr9LHLhC2EYluCDU5NONFZI,394
|
|
38
|
+
pytbox/cli/categraf/__init__.py,sha256=HfhDhWiWEuT5e6fXb6fs7UgoZPwn9WQ1wdFoza2muaI,96
|
|
39
|
+
pytbox/cli/categraf/commands.py,sha256=M-coJaHhb5I9fMW7OMWe9SMrs_RmSm4hSIJ1CPS0Ipc,1874
|
|
40
|
+
pytbox/cli/commands/vm.py,sha256=K3Jf7dFI493raB5v4-SUmnUisVpfX1aQqOZkE5hDE60,559
|
|
41
|
+
pytbox/cli/common/__init__.py,sha256=1_OE4q6OIUQkpwXBWqiKHr7SXxEu925hRgmd2hulIy4,70
|
|
42
|
+
pytbox/cli/common/options.py,sha256=Xv1wXja-fdaQVY6_FzvYRrXDozeTOJV6BL8zYIKJE9k,773
|
|
43
|
+
pytbox/cli/common/utils.py,sha256=0uQ5L1l5cySFheixB91B9ptq0p6tGsBhqvvm3ouRGbI,9050
|
|
44
|
+
pytbox/cli/formatters/__init__.py,sha256=4o85w4j-A-O1oBLvuE9q8AFiJ2C9rvB3MIKsy5VvdfQ,101
|
|
45
|
+
pytbox/cli/formatters/output.py,sha256=h5WhZlQk1rjmxEj88Jy5ODLcv6L5zfGUhks_3AWIkKU,5455
|
|
46
|
+
pytbox/common/__init__.py,sha256=3JWfgCQZKZuSH5NCE7OCzKwq82pkyop9l7sH5YSNyfU,122
|
|
47
|
+
pytbox/database/mongo.py,sha256=AhJ9nCAQHKrrcL-ujeonOwEf3x2QkmT2VhoCdglqJmU,3478
|
|
48
|
+
pytbox/database/victoriametrics.py,sha256=iSgYLcINpWK3ry1fWoL32k65j91Ag49kNBWXYxW3NKA,15750
|
|
49
|
+
pytbox/feishu/client.py,sha256=kwGLseGT_iQUFmSqpuS2_77WmxtHstD64nXvktuQ3B4,5865
|
|
50
|
+
pytbox/feishu/endpoints.py,sha256=z3nPOZPC2JGDJlO7SusWBpRA33hZZ4Z-GBhI6F8L_u4,40240
|
|
51
|
+
pytbox/feishu/errors.py,sha256=79qFAHZw7jDj3gnWAjI1-W4tB0q1_aSfdjee4xzXeuI,1179
|
|
52
|
+
pytbox/feishu/helpers.py,sha256=jhSkHiUw4822QBXx2Jw8AksogZdakZ-3QqvC3lB3qEI,201
|
|
53
|
+
pytbox/feishu/typing.py,sha256=3hWkJgOi-v2bt9viMxkyvNHsPgrbAa0aZOxsZYg2vdM,122
|
|
54
|
+
pytbox/log/logger.py,sha256=t5LEvuYTDixh67JOyX0ke1ukb9kT5PEaUSsQnDDck90,8921
|
|
55
|
+
pytbox/log/victorialog.py,sha256=gffEiq38adv9sC5oZeMcyKghd3SGfRuqtZOFuqHQF6E,4139
|
|
56
|
+
pytbox/mail/alimail.py,sha256=njKA3PUbIaiKFaxKvUObmklmEEHg2YA-O5rpgsgT5_w,5147
|
|
57
|
+
pytbox/mail/client.py,sha256=RNgWhhTXFTpD43U4p7hbmnfRdmltuZmbm890gaZTzhI,6278
|
|
58
|
+
pytbox/mail/mail_detail.py,sha256=6u8DK-7WzYPSuX6TdicSCh2Os_9Ou6Rn9xc6WRvv85M,699
|
|
59
|
+
pytbox/network/meraki.py,sha256=OdT5PWNYiPcJfsQ4tMkjKSE22EH1xBHHG-vuv0L4jM8,20064
|
|
60
|
+
pytbox/utils/cronjob.py,sha256=b17CY1fmaFTdQojicXAXHliov_JZdmT7cZhtO4v5sCo,3080
|
|
61
|
+
pytbox/utils/env.py,sha256=gD2-NyL3K3Vg1B1eGeD1hRtlSHPGgF8Oi9mchuQL6_o,646
|
|
62
|
+
pytbox/utils/load_config.py,sha256=R4pGerBinbewsym41hQ8Z-I5I7gepuEKODjIrli4C08,5043
|
|
63
|
+
pytbox/utils/load_vm_devfile.py,sha256=GVbB-FvGb0l586SDaraz__ZaXyDWd1WxcXVw5xGfXWw,1328
|
|
64
|
+
pytbox/utils/response.py,sha256=kXjlwt0WVmLRam2eu1shzX2cQ7ux4cCQryaPGYwle5g,1247
|
|
65
|
+
pytbox/utils/richutils.py,sha256=Qy7DB8dowt2lINp07RfDCyd8EXpbdvlKslVnjiMn-5o,863
|
|
66
|
+
pytbox/utils/timeutils.py,sha256=YqPZC3DVm0RjIxesBZQfKkT6LlJcuJy1a1r3rHMveng,18366
|
|
67
|
+
pytbox/win/ad.py,sha256=-3pWfL3dElz-XoO4j4M9lrgu3KJtlhrS9gCWJBpafAU,1147
|
|
68
|
+
pytbox-0.3.1.dist-info/METADATA,sha256=2JNJeSTV8TvbLWDcbgalpqYnhBsbXzHspe-ORSksCyI,6319
|
|
69
|
+
pytbox-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
70
|
+
pytbox-0.3.1.dist-info/entry_points.txt,sha256=YaTOJ2oPjOiv2SZwY0UC-UA9QS2phRH1oMvxGnxO0Js,43
|
|
71
|
+
pytbox-0.3.1.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
|
|
72
|
+
pytbox-0.3.1.dist-info/RECORD,,
|
pytbox/utils/ping_checker.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
pytbox-0.0.7.dist-info/RECORD
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
pytbox/base.py,sha256=_SpfeIiJE4xbQMsYghnMehcNzHP-mBfrKONX43b0OQk,1490
|
|
2
|
-
pytbox/cli.py,sha256=N775a0GK80IT2lQC2KRYtkZpIiu9UjavZmaxgNUgJhQ,160
|
|
3
|
-
pytbox/dida365.py,sha256=pUMPB9AyLZpTTbaz2LbtzdEpyjvuGf4YlRrCvM5sbJo,10545
|
|
4
|
-
pytbox/onepassword_connect.py,sha256=nD3xTl1ykQ4ct_dCRRF138gXCtk-phPfKYXuOn-P7Z8,3064
|
|
5
|
-
pytbox/onepassword_sa.py,sha256=08iUcYud3aEHuQcUsem9bWNxdXKgaxFbMy9yvtr-DZQ,6995
|
|
6
|
-
pytbox/alert/alert_handler.py,sha256=FePPQS4LyGphSJ0QMv0_pLWaXxEqsRlcTKMfUjtsNfk,5048
|
|
7
|
-
pytbox/alert/ping.py,sha256=g36X0U3U8ndZqfpVIcuoxJJ0X5gST3I_IwjTQC1roHA,779
|
|
8
|
-
pytbox/alicloud/sls.py,sha256=UR4GdI86dCKAFI2xt_1DELu7q743dpd3xrYtuNpfC5A,4065
|
|
9
|
-
pytbox/categraf/build_config.py,sha256=DBBKjqCJZ3a6BbVuJbN_C573Z-K3p43iDbB9Ahaw3Tw,2944
|
|
10
|
-
pytbox/cli/__init__.py,sha256=5ID4-oXrMsHFcfDsQeXDYeThPOuQ1Fl2x2kHWfgfOEw,67
|
|
11
|
-
pytbox/cli/main.py,sha256=S-DBp-1d0BCpvZ7jRE3bYmhKSiPpCJHFGsbdVF485BY,322
|
|
12
|
-
pytbox/cli/categraf/__init__.py,sha256=HfhDhWiWEuT5e6fXb6fs7UgoZPwn9WQ1wdFoza2muaI,96
|
|
13
|
-
pytbox/cli/categraf/commands.py,sha256=M-coJaHhb5I9fMW7OMWe9SMrs_RmSm4hSIJ1CPS0Ipc,1874
|
|
14
|
-
pytbox/cli/common/__init__.py,sha256=1_OE4q6OIUQkpwXBWqiKHr7SXxEu925hRgmd2hulIy4,70
|
|
15
|
-
pytbox/cli/common/options.py,sha256=Xv1wXja-fdaQVY6_FzvYRrXDozeTOJV6BL8zYIKJE9k,773
|
|
16
|
-
pytbox/cli/common/utils.py,sha256=0uQ5L1l5cySFheixB91B9ptq0p6tGsBhqvvm3ouRGbI,9050
|
|
17
|
-
pytbox/cli/formatters/__init__.py,sha256=4o85w4j-A-O1oBLvuE9q8AFiJ2C9rvB3MIKsy5VvdfQ,101
|
|
18
|
-
pytbox/cli/formatters/output.py,sha256=h5WhZlQk1rjmxEj88Jy5ODLcv6L5zfGUhks_3AWIkKU,5455
|
|
19
|
-
pytbox/common/__init__.py,sha256=3JWfgCQZKZuSH5NCE7OCzKwq82pkyop9l7sH5YSNyfU,122
|
|
20
|
-
pytbox/database/mongo.py,sha256=CSpHC7iR-M0BaVxXz5j6iXjMKPgXJX_G7MrjCj5Gm8Q,3478
|
|
21
|
-
pytbox/database/victoriametrics.py,sha256=PfeshtlgZNfbiq7Fo4ibJruWYeAKryBXu8ckl8YC1jM,4389
|
|
22
|
-
pytbox/feishu/client.py,sha256=kwGLseGT_iQUFmSqpuS2_77WmxtHstD64nXvktuQ3B4,5865
|
|
23
|
-
pytbox/feishu/endpoints.py,sha256=KmLB7yq0mpJgkWsTgGCufrejrPGV6JP0_p1GE6Pp4yI,40264
|
|
24
|
-
pytbox/feishu/errors.py,sha256=79qFAHZw7jDj3gnWAjI1-W4tB0q1_aSfdjee4xzXeuI,1179
|
|
25
|
-
pytbox/feishu/helpers.py,sha256=jhSkHiUw4822QBXx2Jw8AksogZdakZ-3QqvC3lB3qEI,201
|
|
26
|
-
pytbox/feishu/typing.py,sha256=3hWkJgOi-v2bt9viMxkyvNHsPgrbAa0aZOxsZYg2vdM,122
|
|
27
|
-
pytbox/log/logger.py,sha256=7ZisXRxLb_MVbIqlYHWoTbj1EA0Z4G5SZvITlt1IKW8,7416
|
|
28
|
-
pytbox/log/victorialog.py,sha256=gffEiq38adv9sC5oZeMcyKghd3SGfRuqtZOFuqHQF6E,4139
|
|
29
|
-
pytbox/utils/env.py,sha256=jO_-BKbGuDU7lIL9KYkcxGCzQwTXfxD4mIYtSAjREmI,622
|
|
30
|
-
pytbox/utils/load_config.py,sha256=wNCDPLH7xet5b9pUlTz6VsBejRsJZ7LP85wWMaITBYg,3042
|
|
31
|
-
pytbox/utils/ping_checker.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
|
32
|
-
pytbox/utils/response.py,sha256=kXjlwt0WVmLRam2eu1shzX2cQ7ux4cCQryaPGYwle5g,1247
|
|
33
|
-
pytbox/utils/richutils.py,sha256=OT9_q2Q1bthzB0g1GlhZVvM4ZAepJRKL6a_Vsr6vEqo,487
|
|
34
|
-
pytbox/utils/timeutils.py,sha256=XbK2KB-SVi7agNqoQN7i40wysrZvrGuwebViv1Cw-Ok,20226
|
|
35
|
-
pytbox-0.0.7.dist-info/METADATA,sha256=veBpwrGnlKlCI5E9XVzVYmW2dVsLQXqSgeMXe0F2cXU,6245
|
|
36
|
-
pytbox-0.0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
37
|
-
pytbox-0.0.7.dist-info/entry_points.txt,sha256=YaTOJ2oPjOiv2SZwY0UC-UA9QS2phRH1oMvxGnxO0Js,43
|
|
38
|
-
pytbox-0.0.7.dist-info/top_level.txt,sha256=YADgWue-Oe128ptN3J2hS3GB0Ncc5uZaSUM3e1rwswE,7
|
|
39
|
-
pytbox-0.0.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|