dts-dance 0.2.5__py3-none-any.whl → 0.2.8__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.
- {dts_dance-0.2.5.dist-info → dts_dance-0.2.8.dist-info}/METADATA +2 -2
- dts_dance-0.2.8.dist-info/RECORD +16 -0
- dtsdance/bytecloud.py +8 -3
- dtsdance/ddutil.py +13 -0
- dtsdance/dflow.py +16 -20
- dtsdance/dsyncer.py +4 -4
- dtsdance/spacex.py +8 -8
- dtsdance/tcc_inner.py +2 -2
- dtsdance/tce.py +289 -0
- dts_dance-0.2.5.dist-info/RECORD +0 -15
- {dts_dance-0.2.5.dist-info → dts_dance-0.2.8.dist-info}/WHEEL +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dts-dance
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: dts dance lib
|
|
5
5
|
Keywords: observation,tools
|
|
6
6
|
Requires-Python: >=3.12
|
|
7
|
-
Requires-Dist: boto3>=1.42.
|
|
7
|
+
Requires-Dist: boto3>=1.42.35
|
|
8
8
|
Requires-Dist: loguru<0.8.0,>=0.7.3
|
|
9
9
|
Requires-Dist: pyyaml<7.0.0,>=6.0.3
|
|
10
10
|
Requires-Dist: requests-toolbelt==1.0.0
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
dtsdance/__init__.py,sha256=Yl_jEZ5weYfcrklnDvwB4wSgCOvMBLRRgWx0gHs3qfM,49
|
|
2
|
+
dtsdance/bytecloud.py,sha256=LZ-uw5NMmapyNpt89bMKhCgv4U2cGR-XjLzFFFEXGxM,5899
|
|
3
|
+
dtsdance/ddutil.py,sha256=1ZUmW11nw8WW1NfAIRbjuKy8zeQVTFvoXl6QY3o4YJ0,1534
|
|
4
|
+
dtsdance/dflow.py,sha256=v6tQv9O6-xjXhNuU14vys0lIxi4hKKv27nuBjLgRk6Y,7747
|
|
5
|
+
dtsdance/dsyncer.py,sha256=PCatQIFXgi1l2qT60zNN-ALAqtv7_sg-D2oNMB_t8qw,9906
|
|
6
|
+
dtsdance/feishu_base.py,sha256=dYYNnsCjGZYN2I6inR9FRQoUiDLB7j40rzydw50N38o,11825
|
|
7
|
+
dtsdance/feishu_table.py,sha256=JleCjQJ-rcbC15v2UAc5BK-YioB2SMGsdGztQ9BaT4k,10779
|
|
8
|
+
dtsdance/metrics_fe.py,sha256=hzIl5BJmuCrkqJOHELVzXm3YAqrPttbyVkKBglS4mgQ,18978
|
|
9
|
+
dtsdance/s3.py,sha256=Bh-cwLksfO5PewNtIzE_Md3rRLDLI1DUVoOD7Pou5T8,1294
|
|
10
|
+
dtsdance/spacex.py,sha256=W_YGt_Wo_Cy4eDhgXhNfskayPHcZ1kg2Mil2ghI_VLE,4791
|
|
11
|
+
dtsdance/tcc_inner.py,sha256=QqVyhwP0kCdp1HFHFgtme9o0im-eQNn1HVGdLt3Xr8g,1627
|
|
12
|
+
dtsdance/tcc_open.py,sha256=JIfVhL3yfm0ftS_vzONE2QNzfqcZuX1mPTvjovAtwmE,6893
|
|
13
|
+
dtsdance/tce.py,sha256=QwqPimZu0GKeP--sdbMP9h1e22nGuZL2FHqBUykXDOw,11563
|
|
14
|
+
dts_dance-0.2.8.dist-info/METADATA,sha256=YjipvJ24oD--koIvidnlXrhll5UzI5Efpl-Zog_kQZc,826
|
|
15
|
+
dts_dance-0.2.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
16
|
+
dts_dance-0.2.8.dist-info/RECORD,,
|
dtsdance/bytecloud.py
CHANGED
|
@@ -145,18 +145,23 @@ class ByteCloudClient:
|
|
|
145
145
|
site_config = self.get_site_config(site)
|
|
146
146
|
return self._acquire_jwt_token(site_config.endpoint, site_config.svc_secret)
|
|
147
147
|
|
|
148
|
-
def build_request_headers(self, site: str) -> dict[str, str]:
|
|
148
|
+
def build_request_headers(self, site: str, vregion: str | None = None) -> dict[str, str]:
|
|
149
149
|
"""
|
|
150
150
|
构建请求头
|
|
151
151
|
|
|
152
152
|
Args:
|
|
153
153
|
site: 站点名称
|
|
154
|
-
|
|
154
|
+
vregion: 默认为 None
|
|
155
155
|
Returns:
|
|
156
156
|
dict[str, str]: 请求头字典
|
|
157
157
|
"""
|
|
158
158
|
jwt_token = self.get_jwt_token(site)
|
|
159
|
-
|
|
159
|
+
headers = {"Content-Type": "application/json", "x-jwt-token": jwt_token}
|
|
160
|
+
if vregion:
|
|
161
|
+
headers["x-bcgw-vregion"] = vregion
|
|
162
|
+
headers["get-svc"] = "1" # response header 中显示实际请求的机房
|
|
163
|
+
|
|
164
|
+
return headers
|
|
160
165
|
|
|
161
166
|
def get_site_config(self, site: str) -> SiteConfig:
|
|
162
167
|
"""
|
dtsdance/ddutil.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Any, Optional
|
|
2
2
|
from loguru import logger
|
|
3
3
|
import requests
|
|
4
|
+
import json
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def make_request(method: str, url: str, headers: dict[str, str], payload: Optional[dict] = None) -> dict[str, Any]:
|
|
@@ -37,3 +38,15 @@ def make_request(method: str, url: str, headers: dict[str, str], payload: Option
|
|
|
37
38
|
error_msg += f", response.text: {response.text}"
|
|
38
39
|
logger.warning(error_msg)
|
|
39
40
|
raise
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def output_curl(url: str, headers: dict[str, str], payload: dict) -> str:
|
|
44
|
+
"""
|
|
45
|
+
生成等效的 curl 命令字符串
|
|
46
|
+
"""
|
|
47
|
+
curl_headers = " \\\n ".join([f"-H '{k}: {v}'" for k, v in headers.items()])
|
|
48
|
+
curl_payload = json.dumps(payload, ensure_ascii=False)
|
|
49
|
+
curl_cmd = f"""curl -X POST '{url}' \\
|
|
50
|
+
{curl_headers} \\
|
|
51
|
+
-d '{curl_payload}'"""
|
|
52
|
+
return curl_cmd
|
dtsdance/dflow.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import collections
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any
|
|
3
3
|
from loguru import logger
|
|
4
4
|
|
|
5
|
-
from dtsdance.ddutil import make_request
|
|
5
|
+
from dtsdance.ddutil import make_request, output_curl
|
|
6
6
|
from .bytecloud import ByteCloudClient
|
|
7
7
|
|
|
8
8
|
|
|
@@ -19,12 +19,6 @@ class DFlowClient:
|
|
|
19
19
|
def __init__(self, bytecloud_client: ByteCloudClient) -> None:
|
|
20
20
|
self.bytecloud_client = bytecloud_client
|
|
21
21
|
|
|
22
|
-
def build_request_headers(self, site: str, vregion: str | None) -> dict[str, str]:
|
|
23
|
-
headers = self.bytecloud_client.build_request_headers(site)
|
|
24
|
-
if vregion:
|
|
25
|
-
headers["x-bcgw-vregion"] = vregion
|
|
26
|
-
return headers
|
|
27
|
-
|
|
28
22
|
def get_task_info(self, site: str, task_id: str, vregion: str | None = None) -> dict[str, Any]:
|
|
29
23
|
"""
|
|
30
24
|
获取 DFlow 任务信息
|
|
@@ -43,7 +37,7 @@ class DFlowClient:
|
|
|
43
37
|
# 构建请求数据
|
|
44
38
|
payload = {"id": int(task_id)}
|
|
45
39
|
|
|
46
|
-
response_data = make_request("POST", url, self.build_request_headers(site, vregion), payload)
|
|
40
|
+
response_data = make_request("POST", url, self.bytecloud_client.build_request_headers(site, vregion), payload)
|
|
47
41
|
|
|
48
42
|
message = response_data.get("message")
|
|
49
43
|
# logger.debug(f"get_task_info {site} {task_id}, message: {message}")
|
|
@@ -52,8 +46,7 @@ class DFlowClient:
|
|
|
52
46
|
raise TaskNotFound(f"获取 DFlow 任务信息失败,站点: {site}, 任务 ID: {task_id} 不存在")
|
|
53
47
|
|
|
54
48
|
try:
|
|
55
|
-
|
|
56
|
-
task = cast(dict, data.get("task", {}))
|
|
49
|
+
task = response_data.get("data", {}).get("task", {})
|
|
57
50
|
# 提取核心信息
|
|
58
51
|
filtered_data = {
|
|
59
52
|
"task_id": task.get("id", ""),
|
|
@@ -85,7 +78,7 @@ class DFlowClient:
|
|
|
85
78
|
# 构建请求数据
|
|
86
79
|
payload = {"dflow_id": int(dflow_id)}
|
|
87
80
|
|
|
88
|
-
response_data = make_request("POST", url, self.build_request_headers(site, vregion), payload)
|
|
81
|
+
response_data = make_request("POST", url, self.bytecloud_client.build_request_headers(site, vregion), payload)
|
|
89
82
|
|
|
90
83
|
message = response_data.get("message", "")
|
|
91
84
|
# logger.debug(f"get_dflow_info {site} {dflow_id}, message: {message}")
|
|
@@ -94,8 +87,7 @@ class DFlowClient:
|
|
|
94
87
|
raise DFlowNotFound(f"获取 DFlow 进程信息失败,站点: {site}, 进程 ID: {dflow_id} 不存在")
|
|
95
88
|
|
|
96
89
|
try:
|
|
97
|
-
|
|
98
|
-
dflow = cast(dict, data.get("dflow", {}))
|
|
90
|
+
dflow = response_data.get("data", {}).get("dflow", {})
|
|
99
91
|
# 提取核心信息
|
|
100
92
|
filtered_data = {
|
|
101
93
|
"dflow_id": dflow.get("id", ""),
|
|
@@ -125,12 +117,13 @@ class DFlowClient:
|
|
|
125
117
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
126
118
|
return f"{site_info.endpoint}/bytedts/datasync/detail/{task_id}"
|
|
127
119
|
|
|
128
|
-
def init_resources(self, site: str, ctrl_env: str) -> bool:
|
|
120
|
+
def init_resources(self, site: str, vregion: str, ctrl_env: str) -> bool:
|
|
129
121
|
"""
|
|
130
122
|
初始化 CTRL 环境资源
|
|
131
123
|
|
|
132
124
|
Args:
|
|
133
125
|
site: 站点名称
|
|
126
|
+
vregion: 虚拟区域
|
|
134
127
|
ctrl_env: 控制环境
|
|
135
128
|
|
|
136
129
|
Returns:
|
|
@@ -143,21 +136,21 @@ class DFlowClient:
|
|
|
143
136
|
# 构建请求数据
|
|
144
137
|
payload = {"ctrl_env": ctrl_env}
|
|
145
138
|
|
|
146
|
-
response_data = make_request("POST", url, self.build_request_headers(site,
|
|
139
|
+
response_data = make_request("POST", url, self.bytecloud_client.build_request_headers(site, vregion), payload)
|
|
147
140
|
|
|
148
141
|
message = response_data.get("message")
|
|
149
142
|
logger.info(f"int_resources {site} {ctrl_env}, message: {message}")
|
|
150
143
|
|
|
151
144
|
return message == "ok"
|
|
152
145
|
|
|
153
|
-
def list_resources(self, site: str, ctrl_env: str) -> list[str]:
|
|
146
|
+
def list_resources(self, site: str, vregion: str, ctrl_env: str) -> list[str]:
|
|
154
147
|
"""
|
|
155
148
|
列举 CTRL 环境资源列表,连同 agent 列表
|
|
156
149
|
|
|
157
150
|
Args:
|
|
158
151
|
site: 站点名称
|
|
152
|
+
vregion: 虚拟区域
|
|
159
153
|
ctrl_env: 控制环境
|
|
160
|
-
|
|
161
154
|
Returns:
|
|
162
155
|
list[str]: CTRL 环境资源列表
|
|
163
156
|
"""
|
|
@@ -166,9 +159,12 @@ class DFlowClient:
|
|
|
166
159
|
url = f"{site_info.endpoint}/api/v1/bytedts/api/bytedts/v3/DescribeResources"
|
|
167
160
|
|
|
168
161
|
# 构建请求数据
|
|
162
|
+
headers = self.bytecloud_client.build_request_headers(site, vregion)
|
|
169
163
|
payload = {"offset": 0, "limit": 10, "ctrl_env": ctrl_env}
|
|
164
|
+
response_data = make_request("POST", url, headers, payload)
|
|
170
165
|
|
|
171
|
-
|
|
166
|
+
# curl_cmd = output_curl(url, headers, payload)
|
|
167
|
+
# print(f"Equivalent curl:\n{curl_cmd}")
|
|
172
168
|
|
|
173
169
|
try:
|
|
174
170
|
data = response_data.get("data", {})
|
|
@@ -181,7 +177,7 @@ class DFlowClient:
|
|
|
181
177
|
"""获取所有可用的控制环境列表,返回以domain为键,ctrl_env列表为值的字典"""
|
|
182
178
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
183
179
|
url = f"{site_info.endpoint}/api/v1/bytedts/api/bytedts/v3/DescribeRegions"
|
|
184
|
-
resp_json = make_request("POST", url, self.build_request_headers(site, None), {})
|
|
180
|
+
resp_json = make_request("POST", url, self.bytecloud_client.build_request_headers(site, None), {})
|
|
185
181
|
if resp_json["code"] != 0:
|
|
186
182
|
raise Exception(resp_json["message"])
|
|
187
183
|
|
dtsdance/dsyncer.py
CHANGED
|
@@ -21,7 +21,7 @@ class DSyncerClient:
|
|
|
21
21
|
self.envs = envs
|
|
22
22
|
self.bytecloud_client = bytecloud_client
|
|
23
23
|
|
|
24
|
-
def _build_headers(self,
|
|
24
|
+
def _build_headers(self, site: str, secret_api: bool = False) -> dict[str, str]:
|
|
25
25
|
"""
|
|
26
26
|
构建请求头
|
|
27
27
|
|
|
@@ -32,11 +32,11 @@ class DSyncerClient:
|
|
|
32
32
|
Returns:
|
|
33
33
|
dict[str, str]: 请求头字典
|
|
34
34
|
"""
|
|
35
|
-
jwt_token = self.bytecloud_client.get_jwt_token(
|
|
36
|
-
headers = {"X-Jwt-Token": jwt_token
|
|
35
|
+
jwt_token = self.bytecloud_client.get_jwt_token(site)
|
|
36
|
+
headers = {"X-Jwt-Token": jwt_token}
|
|
37
37
|
|
|
38
38
|
if secret_api:
|
|
39
|
-
token = self.envs[
|
|
39
|
+
token = self.envs[site].token
|
|
40
40
|
headers["Authorization"] = f"Token {token}"
|
|
41
41
|
|
|
42
42
|
return headers
|
dtsdance/spacex.py
CHANGED
|
@@ -40,11 +40,11 @@ class SpaceXClient:
|
|
|
40
40
|
logger.warning(f"do quest queryServerMeta exception: {e}")
|
|
41
41
|
raise
|
|
42
42
|
|
|
43
|
-
def register_resource(self, site: str,
|
|
43
|
+
def register_resource(self, site: str, payload: dict[str, Any]) -> bool:
|
|
44
44
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
45
45
|
url = f"{site_info.endpoint_bytedts_spacex}/resource/v1/registerResource"
|
|
46
46
|
try:
|
|
47
|
-
response = requests.post(url, json=
|
|
47
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site))
|
|
48
48
|
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
49
49
|
|
|
50
50
|
response.raise_for_status()
|
|
@@ -56,11 +56,11 @@ class SpaceXClient:
|
|
|
56
56
|
logger.warning(f"do quest registerResource exception: {e}")
|
|
57
57
|
raise
|
|
58
58
|
|
|
59
|
-
def list_resources(self, site: str,
|
|
59
|
+
def list_resources(self, site: str, payload: dict[str, Any]) -> list[str]:
|
|
60
60
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
61
61
|
url = f"{site_info.endpoint_bytedts_spacex}/resource/v1/listResource"
|
|
62
62
|
try:
|
|
63
|
-
response = requests.post(url, json=
|
|
63
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site))
|
|
64
64
|
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
65
65
|
|
|
66
66
|
response.raise_for_status()
|
|
@@ -78,7 +78,7 @@ class SpaceXClient:
|
|
|
78
78
|
def register_gateway(self, site: str, gateway_info: GatewayInfo) -> bool:
|
|
79
79
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
80
80
|
url = f"{site_info.endpoint_bytedts_spacex}/bytedts/v1/registryGateway"
|
|
81
|
-
|
|
81
|
+
payload = {
|
|
82
82
|
"region": gateway_info.mgr_name,
|
|
83
83
|
"server_region": gateway_info.mgr_name,
|
|
84
84
|
"cluster_region": gateway_info.ctrl_name,
|
|
@@ -97,7 +97,7 @@ class SpaceXClient:
|
|
|
97
97
|
"unified_tao_service": 1,
|
|
98
98
|
}
|
|
99
99
|
try:
|
|
100
|
-
response = requests.post(url, json=
|
|
100
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site))
|
|
101
101
|
response.raise_for_status()
|
|
102
102
|
|
|
103
103
|
result = response.json()
|
|
@@ -107,11 +107,11 @@ class SpaceXClient:
|
|
|
107
107
|
logger.warning(f"do quest registryGateway exception: {e}")
|
|
108
108
|
raise
|
|
109
109
|
|
|
110
|
-
def gateway_operation(self, site: str, operation: str,
|
|
110
|
+
def gateway_operation(self, site: str, operation: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
111
111
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
112
112
|
url = f"{site_info.endpoint_bytedts_spacex}/bytedts/v1/{operation}"
|
|
113
113
|
try:
|
|
114
|
-
response = requests.post(url, json=
|
|
114
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site))
|
|
115
115
|
# print(f"response status code: {response.status_code}, response text: {response.text}")
|
|
116
116
|
|
|
117
117
|
response.raise_for_status()
|
dtsdance/tcc_inner.py
CHANGED
|
@@ -27,7 +27,7 @@ class TCCInnerClient:
|
|
|
27
27
|
site_info = self.bytecloud_client.get_site_config(site)
|
|
28
28
|
url = f"{site_info.endpoint}/api/v3/tcc/bcc/config/list_v2"
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
payload = {
|
|
31
31
|
"ns_name": ns_name,
|
|
32
32
|
"region": region,
|
|
33
33
|
"dir_path": dir,
|
|
@@ -40,7 +40,7 @@ class TCCInnerClient:
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
try:
|
|
43
|
-
response = requests.post(url, headers=self.bytecloud_client.build_request_headers(site), json=
|
|
43
|
+
response = requests.post(url, headers=self.bytecloud_client.build_request_headers(site), json=payload, timeout=30)
|
|
44
44
|
response.raise_for_status()
|
|
45
45
|
result = response.json()
|
|
46
46
|
|
dtsdance/tce.py
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
import requests
|
|
3
|
+
|
|
4
|
+
from .bytecloud import ByteCloudClient
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TCEError(Exception):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TCEErrorServiceExist(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TCEErrorClusterExist(Exception):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TCEClient:
|
|
20
|
+
"""Client for TCE deployment API."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, bytecloud_client: ByteCloudClient) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Initialize TCE client.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
base_url: TCE API base URL
|
|
28
|
+
jwt_token: JWT token for authentication (can be fetched automatically)
|
|
29
|
+
"""
|
|
30
|
+
self.bytecloud_client = bytecloud_client
|
|
31
|
+
|
|
32
|
+
def create_service(self, site: str, ctrl_name: str, bytetree_parent_id: int) -> int | None:
|
|
33
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
34
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/deployment/service/create/"
|
|
35
|
+
|
|
36
|
+
service_info = {
|
|
37
|
+
"meta": {"name": f"bytedts.cm.{ctrl_name}", "psm": f"bytedts.cm.{ctrl_name}", "env": "prod"},
|
|
38
|
+
"auth": {
|
|
39
|
+
"galaxy_info": {"parent_id": bytetree_parent_id},
|
|
40
|
+
"approval_controls": ["reset"],
|
|
41
|
+
"iam_info": {"owners": [{"username": site_info.svc_account}, {"username": "mahang"}]},
|
|
42
|
+
"owner_name": site_info.svc_account,
|
|
43
|
+
},
|
|
44
|
+
"extra_features": {
|
|
45
|
+
"service_token": {
|
|
46
|
+
"tech_stack": {"language": "go", "framework": "custom", "platform_types_v_2": {"tce": ["http"]}},
|
|
47
|
+
"deploy": {"type": "stateless_compute", "scale": {"enable": True}, "descale": {"enable": True}},
|
|
48
|
+
"level": "P2",
|
|
49
|
+
"purpose": "convention",
|
|
50
|
+
"contain_user_personal_info": False,
|
|
51
|
+
"data_sensitivity_level": "L2",
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"build": {
|
|
55
|
+
"dependency_mode": "default",
|
|
56
|
+
"base_image": "debian.bookworm.tce_service:latest",
|
|
57
|
+
"install_package_info": [],
|
|
58
|
+
"scm_repo_info": [
|
|
59
|
+
{"name": "bytedts/dflow/dtscm", "remote_id": 387073, "main_repo": True, "path": "dts-cm"},
|
|
60
|
+
{"name": "toutiao/load", "remote_id": 667, "path": "toutiao/load"},
|
|
61
|
+
{"name": "toutiao/runtime", "remote_id": 631, "path": "toutiao/runtime"},
|
|
62
|
+
],
|
|
63
|
+
"language": "go",
|
|
64
|
+
"framework_support": "none",
|
|
65
|
+
"tech_stack": "custom",
|
|
66
|
+
},
|
|
67
|
+
"runtime": {
|
|
68
|
+
"umount_ss_conf": False,
|
|
69
|
+
"new_ports": [
|
|
70
|
+
{"intent": "primary", "port": 8088, "is_primary": True, "type": "tcp"},
|
|
71
|
+
{"intent": "other", "port": 3033, "is_primary": False, "type": "tcp"},
|
|
72
|
+
],
|
|
73
|
+
"is_runtime": False,
|
|
74
|
+
"app_path": "dts-cm/bootstrap.sh",
|
|
75
|
+
"enable_iast": False,
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
payload = {"service_info": service_info}
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
83
|
+
if response.status_code != 200:
|
|
84
|
+
if "already exists" in response.text:
|
|
85
|
+
raise TCEErrorServiceExist("TCE cluster with the same name already exists")
|
|
86
|
+
|
|
87
|
+
raise TCEError(f"TCE API request failed with status {response.status_code}\n" f"Response: {response.text}")
|
|
88
|
+
|
|
89
|
+
result = response.json()
|
|
90
|
+
if result.get("code", 0) == -1:
|
|
91
|
+
raise TCEError(f"TCE API error: {result.get('error')}")
|
|
92
|
+
|
|
93
|
+
return result.get("data", {}).get("service", 0)
|
|
94
|
+
|
|
95
|
+
except requests.RequestException as e:
|
|
96
|
+
raise TCEError(f"Failed to create TCE cluster: {str(e)}") from e
|
|
97
|
+
|
|
98
|
+
def create_cluster(self, site: str, cluster_info: dict[str, Any], service: int) -> int | None:
|
|
99
|
+
"""
|
|
100
|
+
Create TCE cluster.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
cluster_info: Cluster configuration (meta, resource, runtime)
|
|
104
|
+
service: Service ID
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
The created cluster ID, or None if creation failed
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
TCEError: If API call fails
|
|
111
|
+
"""
|
|
112
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
113
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/deployment/cluster/create/"
|
|
114
|
+
payload = {"cluster_info": cluster_info, "service": service}
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
118
|
+
if response.status_code != 200:
|
|
119
|
+
if "a same named TCE cluster already exists" in response.text:
|
|
120
|
+
raise TCEErrorClusterExist("TCE cluster with the same name already exists")
|
|
121
|
+
|
|
122
|
+
raise TCEError(f"TCE API request failed with status {response.status_code}\n" f"Response: {response.text}")
|
|
123
|
+
|
|
124
|
+
result = response.json()
|
|
125
|
+
|
|
126
|
+
# Check for errors in response
|
|
127
|
+
if not isinstance(result, dict):
|
|
128
|
+
raise TCEError(f"Unexpected response format: {result}")
|
|
129
|
+
|
|
130
|
+
# TCE API may return error information in different formats
|
|
131
|
+
if result.get("code", 0) == -1:
|
|
132
|
+
raise TCEError(f"TCE API error: {result.get('error')}")
|
|
133
|
+
|
|
134
|
+
data = result.get("data", {})
|
|
135
|
+
create_success = data.get("deployment_type", "") == "create" and data.get("status", "") == "pending"
|
|
136
|
+
if not create_success:
|
|
137
|
+
raise TCEError(f"TCE cluster creation failed: {result}")
|
|
138
|
+
|
|
139
|
+
cluster_id = data.get("cluster_info", {}).get("meta", {}).get("id", 0)
|
|
140
|
+
# Ensure cluster_id is an integer
|
|
141
|
+
return int(cluster_id) if cluster_id else 0
|
|
142
|
+
|
|
143
|
+
except requests.RequestException as e:
|
|
144
|
+
raise TCEError(f"Failed to create TCE cluster: {str(e)}") from e
|
|
145
|
+
|
|
146
|
+
def delete_cluster(self, site: str, cluster_id: int, service_id: int, cluster_name: str) -> int | None:
|
|
147
|
+
"""
|
|
148
|
+
Delete TCE cluster (reset/destroy).
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
site: Site identifier
|
|
152
|
+
cluster_id: Cluster ID to delete
|
|
153
|
+
service_id: Service ID
|
|
154
|
+
cluster_name: Cluster name
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
Response data
|
|
158
|
+
|
|
159
|
+
Raises:
|
|
160
|
+
TCEError: If API call fails
|
|
161
|
+
"""
|
|
162
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
163
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/deployment/cluster/reset/"
|
|
164
|
+
payload = {"cluster": cluster_id, "service": service_id}
|
|
165
|
+
|
|
166
|
+
# print(f"Deleting TCE cluster {cluster_id} for service {service_id}")
|
|
167
|
+
try:
|
|
168
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
169
|
+
if response.status_code != 200:
|
|
170
|
+
raise TCEError(f"TCE API request failed with status {response.status_code}\n" f"Response: {response.text}")
|
|
171
|
+
|
|
172
|
+
result = response.json()
|
|
173
|
+
if result.get("code", 0) == -1:
|
|
174
|
+
error_msg = result.get("error", "")
|
|
175
|
+
if "do not exist" in error_msg:
|
|
176
|
+
print(f"cluster {cluster_name} not exist, maybe already deleted")
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
raise TCEError(f"TCE API error: {error_msg}")
|
|
180
|
+
|
|
181
|
+
data = result.get("data", {})
|
|
182
|
+
# 查找 "人工确认" step 的 id
|
|
183
|
+
steps = data.get("steps", [])
|
|
184
|
+
for step in steps:
|
|
185
|
+
if step.get("step_type") == "ConfirmStep":
|
|
186
|
+
return step.get("id")
|
|
187
|
+
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
except requests.RequestException as e:
|
|
191
|
+
raise TCEError(f"Failed to delete TCE cluster: {cluster_name}, msg: {str(e)}") from e
|
|
192
|
+
|
|
193
|
+
def get_cluster_info(self, site: str, cluster_id: int) -> dict[str, Any]:
|
|
194
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
195
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/clusters/{cluster_id}/"
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
response = requests.get(url, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
199
|
+
if response.status_code != 200:
|
|
200
|
+
raise TCEError(f"TCE API request failed with status {response.status_code}\n" f"Response: {response.text}")
|
|
201
|
+
|
|
202
|
+
# print(f"get_cluster_info response.text: {response.text}")
|
|
203
|
+
result = response.json()
|
|
204
|
+
if result.get("code", 0) == -1:
|
|
205
|
+
raise TCEError(f"TCE API error: {result.get('error')}")
|
|
206
|
+
|
|
207
|
+
return result.get("data", {})
|
|
208
|
+
|
|
209
|
+
except requests.RequestException as e:
|
|
210
|
+
raise TCEError(f"Failed to create TCE cluster: {str(e)}") from e
|
|
211
|
+
|
|
212
|
+
def is_cluster_running(self, site: str, cluster_id: int | None) -> bool:
|
|
213
|
+
if cluster_id is None:
|
|
214
|
+
return False
|
|
215
|
+
|
|
216
|
+
cluster_info = self.get_cluster_info(site, cluster_id)
|
|
217
|
+
return cluster_info.get("meta", {}).get("status", "unknown") == "running"
|
|
218
|
+
|
|
219
|
+
def restart_cluster(self, site: str, service_id: int, cluster_id: int) -> list[int]:
|
|
220
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
221
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/deployment/cluster/pod_exec/"
|
|
222
|
+
|
|
223
|
+
payload = {
|
|
224
|
+
"service": service_id,
|
|
225
|
+
"cluster": cluster_id,
|
|
226
|
+
"exec_command": "rebuild",
|
|
227
|
+
"exec_params": {
|
|
228
|
+
"surge_percent": 25,
|
|
229
|
+
"ready_seconds": 10,
|
|
230
|
+
"timeout": 120,
|
|
231
|
+
"tolerance_num": 3,
|
|
232
|
+
"failed_policy": "remain",
|
|
233
|
+
"need_check": True,
|
|
234
|
+
},
|
|
235
|
+
"exec_type": "rebuild",
|
|
236
|
+
"parallel_mode": True,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
241
|
+
if response.status_code != 200:
|
|
242
|
+
raise TCEError(f"TCE API request failed with status {response.status_code}\n" f"Response: {response.text}")
|
|
243
|
+
|
|
244
|
+
result = response.json()
|
|
245
|
+
if result.get("code", 0) == -1:
|
|
246
|
+
raise TCEError(f"TCE API error: {result.get('error')}")
|
|
247
|
+
|
|
248
|
+
steps = result.get("data", {}).get("steps", [])
|
|
249
|
+
step_ids = [step.get("id", 0) for step in steps]
|
|
250
|
+
return step_ids
|
|
251
|
+
|
|
252
|
+
except requests.RequestException as e:
|
|
253
|
+
raise TCEError(f"Failed to create TCE cluster: {str(e)}") from e
|
|
254
|
+
|
|
255
|
+
def confirm_step(self, site: str, step_id: int, action: str = "confirm") -> bool:
|
|
256
|
+
"""
|
|
257
|
+
Confirm a step in TCE cluster deployment.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
step_id: Step ID
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Response data
|
|
264
|
+
|
|
265
|
+
Raises:
|
|
266
|
+
TCEError: If API call fails
|
|
267
|
+
"""
|
|
268
|
+
site_info = self.bytecloud_client.get_site_config(site)
|
|
269
|
+
url = f"{site_info.endpoint}/api/v1/tce/open-apis/v1/deployment_steps/{step_id}/actions/"
|
|
270
|
+
payload = {"action": action}
|
|
271
|
+
|
|
272
|
+
try:
|
|
273
|
+
response = requests.post(url, json=payload, headers=self.bytecloud_client.build_request_headers(site), timeout=60)
|
|
274
|
+
# print(f"Confirm step response: {response.text}")
|
|
275
|
+
|
|
276
|
+
response.raise_for_status()
|
|
277
|
+
result = response.json()
|
|
278
|
+
|
|
279
|
+
# Check for errors in response
|
|
280
|
+
if not isinstance(result, dict):
|
|
281
|
+
raise TCEError(f"Unexpected response format: {result}")
|
|
282
|
+
|
|
283
|
+
if result.get("code", 0) == -1:
|
|
284
|
+
raise TCEError(f"TCE API error: {result.get('error')}")
|
|
285
|
+
|
|
286
|
+
return True
|
|
287
|
+
|
|
288
|
+
except requests.RequestException as e:
|
|
289
|
+
raise TCEError(f"Failed to confirm ticket, msg: {str(e)}") from e
|
dts_dance-0.2.5.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
dtsdance/__init__.py,sha256=Yl_jEZ5weYfcrklnDvwB4wSgCOvMBLRRgWx0gHs3qfM,49
|
|
2
|
-
dtsdance/bytecloud.py,sha256=s1suo-YexMH6gUHYwC6P5k6AeyOm7Q_acYh_gHCDVjI,5654
|
|
3
|
-
dtsdance/ddutil.py,sha256=aZ-fG_e2ZkHs8sxZsudf6bVCnp_OI2Z4WjbxOfPoJRQ,1134
|
|
4
|
-
dtsdance/dflow.py,sha256=lEn_gd0pUOqEhuvs0hSQICR8LKOk3wP4DBbeyHZ-A44,7766
|
|
5
|
-
dtsdance/dsyncer.py,sha256=gK2rRiO3041P3efbmXgvLPeTgKlJowuPR7CCz_uyoSA,9926
|
|
6
|
-
dtsdance/feishu_base.py,sha256=dYYNnsCjGZYN2I6inR9FRQoUiDLB7j40rzydw50N38o,11825
|
|
7
|
-
dtsdance/feishu_table.py,sha256=JleCjQJ-rcbC15v2UAc5BK-YioB2SMGsdGztQ9BaT4k,10779
|
|
8
|
-
dtsdance/metrics_fe.py,sha256=hzIl5BJmuCrkqJOHELVzXm3YAqrPttbyVkKBglS4mgQ,18978
|
|
9
|
-
dtsdance/s3.py,sha256=Bh-cwLksfO5PewNtIzE_Md3rRLDLI1DUVoOD7Pou5T8,1294
|
|
10
|
-
dtsdance/spacex.py,sha256=oVnHXTj-cuq2vcsUJq33_aaq0TQp7A52kldvspKueI4,4799
|
|
11
|
-
dtsdance/tcc_inner.py,sha256=Z0Wr-z2YPwAti6BO_fsX0VPT5pCbfuCBLQ37UKMFL7U,1629
|
|
12
|
-
dtsdance/tcc_open.py,sha256=JIfVhL3yfm0ftS_vzONE2QNzfqcZuX1mPTvjovAtwmE,6893
|
|
13
|
-
dts_dance-0.2.5.dist-info/METADATA,sha256=-skiMz-CuBlzpt7BBDJpOEXrmsj8np_xKnG-6K_HPao,826
|
|
14
|
-
dts_dance-0.2.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
-
dts_dance-0.2.5.dist-info/RECORD,,
|
|
File without changes
|