Skip to content

Commit 77f32dd

Browse files
author
Xinkai Yi
committed
feat: 新增通过对比resource.yaml文件hash值的方式实现网关部署优化
1 parent e65b01c commit 77f32dd

4 files changed

Lines changed: 205 additions & 0 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available.
3+
Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
4+
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://opensource.org/licenses/MIT
7+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
specific language governing permissions and limitations under the License.
10+
"""
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""
2+
Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available.
3+
Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
4+
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://opensource.org/licenses/MIT
7+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
specific language governing permissions and limitations under the License.
10+
"""
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
"""
2+
Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available.
3+
Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
4+
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://opensource.org/licenses/MIT
7+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
specific language governing permissions and limitations under the License.
10+
"""
11+
12+
import hashlib
13+
import os
14+
15+
from django.core.management import call_command
16+
from django.core.management.base import BaseCommand
17+
18+
19+
class Command(BaseCommand):
20+
help = "仅在接口定义发生变化时同步到API网关"
21+
22+
def add_arguments(self, parser):
23+
parser.add_argument(
24+
"--force",
25+
action="store_true",
26+
default=False,
27+
help="强制同步,忽略哈希值对比",
28+
)
29+
30+
def handle(self, *args, **options):
31+
force_sync = options.get("force", False)
32+
33+
# 1. 生成 yaml 文件
34+
self.stdout.write("[Sync] generate definition.yaml")
35+
try:
36+
call_command("generate_definition_yaml")
37+
except Exception as e:
38+
self.stderr.write(
39+
self.style.ERROR(
40+
f"run generate_definition_yaml fail: {e}, "
41+
"please run this command on your development env to find out the reason"
42+
)
43+
)
44+
raise SystemExit(1)
45+
46+
self.stdout.write("[Sync] generate resources.yaml")
47+
try:
48+
call_command("generate_resources_yaml")
49+
except Exception as e:
50+
self.stderr.write(
51+
self.style.ERROR(
52+
f"run generate_resources_yaml fail: {e}, "
53+
"please run this command on your development env to find out the reason"
54+
)
55+
)
56+
raise SystemExit(1)
57+
58+
# 2. 计算当前哈希值(仅计算 resources.yaml)
59+
current_hash = self._calculate_resources_hash()
60+
self.stdout.write(f"[Sync] Current resources.yaml hash: {current_hash[:16]}...")
61+
62+
# 3. 获取上次同步的哈希值
63+
last_hash = self._get_last_sync_hash()
64+
if last_hash:
65+
self.stdout.write(f"[Sync] Last sync hash: {last_hash[:16]}...")
66+
else:
67+
self.stdout.write("[Sync] No previous sync record found")
68+
69+
# 4. 对比决定是否同步
70+
if not force_sync and current_hash == last_hash:
71+
self.stdout.write(self.style.SUCCESS("[Sync] API definition unchanged, skip sync to apigateway"))
72+
# 仍然获取公钥,确保公钥是最新的
73+
self._fetch_public_key()
74+
return
75+
76+
if force_sync:
77+
self.stdout.write(self.style.WARNING("[Sync] Force sync enabled"))
78+
else:
79+
self.stdout.write(self.style.WARNING("[Sync] API definition changed, start syncing..."))
80+
81+
# 5. 执行同步
82+
self.stdout.write("[Sync] sync to apigateway")
83+
try:
84+
call_command("sync_drf_apigateway")
85+
except Exception as e:
86+
self.stderr.write(self.style.ERROR(f"run sync_drf_apigateway fail: {e}"))
87+
# 同步失败时更新状态
88+
self._save_sync_hash(current_hash, success=False)
89+
raise SystemExit(1)
90+
91+
# 6. 获取公钥
92+
self._fetch_public_key()
93+
94+
# 7. 更新哈希值
95+
self._save_sync_hash(current_hash, success=True)
96+
self.stdout.write(self.style.SUCCESS("[Sync] API gateway sync completed successfully"))
97+
98+
def _print_yaml_content(self, filepath, name):
99+
"""打印 YAML 文件内容"""
100+
if os.path.exists(filepath):
101+
self.stdout.write(f"[Sync] the {filepath} content:")
102+
with open(filepath) as f:
103+
self.stdout.write(f.read())
104+
self.stdout.write("====================")
105+
106+
def _calculate_resources_hash(self):
107+
"""计算 resources.yaml 的哈希值"""
108+
filepath = "/app/bk_plugin_runtime/resources.yaml"
109+
if os.path.exists(filepath):
110+
with open(filepath) as f:
111+
content = f.read()
112+
return hashlib.sha256(content.encode()).hexdigest()
113+
return ""
114+
115+
def _get_last_sync_hash(self):
116+
"""从数据库获取上次同步的哈希值"""
117+
try:
118+
from bk_plugin_framework.services.bpf_service.models import (
119+
APIGatewaySyncState,
120+
)
121+
122+
state = APIGatewaySyncState.objects.filter(sync_success=True).first()
123+
return state.api_hash if state else ""
124+
except Exception as e:
125+
self.stdout.write(self.style.WARNING(f"[Sync] Failed to get last sync hash: {e}"))
126+
return ""
127+
128+
def _save_sync_hash(self, hash_value, success=True):
129+
"""保存哈希值到数据库"""
130+
try:
131+
from bk_plugin_framework.services.bpf_service.models import (
132+
APIGatewaySyncState,
133+
)
134+
135+
# 使用 update_or_create,保证只有一条记录
136+
APIGatewaySyncState.objects.update_or_create(
137+
pk=1, defaults={"api_hash": hash_value, "sync_success": success}
138+
)
139+
self.stdout.write(f"[Sync] Sync state saved (success={success})")
140+
except Exception as e:
141+
self.stdout.write(self.style.WARNING(f"[Sync] Failed to save sync hash: {e}"))
142+
143+
def _fetch_public_key(self):
144+
"""获取 API 网关公钥"""
145+
self.stdout.write("[Sync] fetch the public key")
146+
try:
147+
call_command("fetch_apigw_public_key")
148+
except Exception as e:
149+
self.stderr.write(self.style.ERROR(f"run fetch_apigw_public_key fail: {e}"))
150+
raise SystemExit(1)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Tencent is pleased to support the open source community by making 蓝鲸智云 - PaaS平台 (BlueKing - PaaS System) available.
3+
Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
4+
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://opensource.org/licenses/MIT
7+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
8+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
9+
specific language governing permissions and limitations under the License.
10+
"""
11+
12+
from django.db import models
13+
14+
15+
class APIGatewaySyncState(models.Model):
16+
"""API网关同步状态记录
17+
18+
用于存储上次成功同步时的接口定义哈希值,
19+
通过对比哈希值判断是否需要重新同步。
20+
"""
21+
22+
# resources.yaml 的哈希值
23+
api_hash = models.CharField(max_length=64, default="", verbose_name="接口定义哈希值")
24+
# 上次同步时间
25+
last_sync_at = models.DateTimeField(auto_now=True, verbose_name="上次同步时间")
26+
# 同步是否成功
27+
sync_success = models.BooleanField(default=False, verbose_name="同步是否成功")
28+
29+
class Meta:
30+
db_table = "bpf_apigateway_sync_state"
31+
verbose_name = "API网关同步状态"
32+
verbose_name_plural = "API网关同步状态"
33+
34+
def __str__(self):
35+
return f"APIGatewaySyncState(hash={self.api_hash[:16]}..., success={self.sync_success})"

0 commit comments

Comments
 (0)