|
10 | 10 | from django.utils.translation import gettext as _ |
11 | 11 |
|
12 | 12 | from backend.db_meta.enums import TenDBClusterSpiderRole |
13 | | -from backend.db_meta.models import Cluster, Machine |
14 | | -from backend.flow.engine.bamboo.scene.spider.validate.exception import SpiderRoleFailedException |
| 13 | +from backend.db_meta.models import Cluster, Machine, ProxyInstance |
| 14 | +from backend.db_package.models import Package |
| 15 | +from backend.flow.consts import MediumEnum |
| 16 | +from backend.flow.engine.bamboo.scene.spider.validate.exception import ( |
| 17 | + SpiderRoleFailedException, |
| 18 | + UpgradeVersionFailedException, |
| 19 | +) |
15 | 20 | from backend.flow.engine.validate.mysql_base_validate import MysqlBaseValidator |
| 21 | +from backend.flow.utils.mysql.mysql_version_parse import spider_cross_major_version, tspider_version_parse |
16 | 22 |
|
17 | 23 |
|
18 | 24 | class TenDBClusterSpiderUpgradeValidator(MysqlBaseValidator): |
@@ -119,27 +125,167 @@ def pre_check_spider_spec_consistency(self): |
119 | 125 |
|
120 | 126 | return error_msgs |
121 | 127 |
|
| 128 | + def pre_check_spider_upgrade_version_compatibility(self): |
| 129 | + """ |
| 130 | + 检查spider升级版本兼容性 |
| 131 | +
|
| 132 | + 校验逻辑: |
| 133 | + 1. 遍历所有待升级的集群信息 |
| 134 | + 2. 获取目标版本包信息和当前集群所有spider实例版本 |
| 135 | + 3. 确保目标版本大于所有当前版本 |
| 136 | +
|
| 137 | + 返回: |
| 138 | + - list: 错误信息列表,如果没有错误则返回空列表 |
| 139 | + """ |
| 140 | + error_msgs = [] |
| 141 | + |
| 142 | + for info in self.data["infos"]: |
| 143 | + pkg_id = info["pkg_id"] |
| 144 | + cluster_id = info["cluster_id"] |
| 145 | + spider_pkg = Package.objects.get(id=pkg_id, pkg_type=MediumEnum.Spider) |
| 146 | + new_spider_version_num = tspider_version_parse(spider_pkg.name) |
| 147 | + cluster = Cluster.objects.get(id=cluster_id) |
| 148 | + spiders = ProxyInstance.objects.filter(cluster=cluster) |
| 149 | + |
| 150 | + for spider_ins in spiders: |
| 151 | + current_version = tspider_version_parse(spider_ins.version) |
| 152 | + if current_version > new_spider_version_num: |
| 153 | + error_msg = _("集群 {} 待升级版本 {} 需要大于当前版本 {}").format( |
| 154 | + cluster.immute_domain, new_spider_version_num, current_version |
| 155 | + ) |
| 156 | + error_msgs.append(error_msg) |
| 157 | + break # 一个集群发现一个不兼容版本就跳出 |
| 158 | + |
| 159 | + return error_msgs |
| 160 | + |
| 161 | + def pre_check_spider_node_count_compatibility(self): |
| 162 | + """ |
| 163 | + 检查spider节点数量兼容性(仅迁移升级场景) |
| 164 | +
|
| 165 | + 校验逻辑: |
| 166 | + 1. 仅在非本地升级(迁移升级)场景下进行检查 |
| 167 | + 2. 检查新传入的spider master IP数量与现有节点数量是否一致 |
| 168 | + 3. 检查新传入的spider slave IP数量与现有节点数量是否一致 |
| 169 | +
|
| 170 | + 返回: |
| 171 | + - list: 错误信息列表,如果没有错误则返回空列表 |
| 172 | + """ |
| 173 | + error_msgs = [] |
| 174 | + |
| 175 | + # 仅在迁移升级场景下进行检查 |
| 176 | + if self.data.get("upgrade_local", False): |
| 177 | + return error_msgs |
| 178 | + |
| 179 | + for info in self.data["infos"]: |
| 180 | + cluster_id = info["cluster_id"] |
| 181 | + cluster = Cluster.objects.get(id=cluster_id) |
| 182 | + |
| 183 | + spider_master_ip_list = info.get("spider_master_ip_list", []) |
| 184 | + spider_slave_ip_list = info.get("spider_slave_ip_list", []) |
| 185 | + |
| 186 | + master_spiders_count = cluster.proxyinstance_set.filter( |
| 187 | + tendbclusterspiderext__spider_role=TenDBClusterSpiderRole.SPIDER_MASTER |
| 188 | + ).count() |
| 189 | + if master_spiders_count != len(spider_master_ip_list): |
| 190 | + error_msg = _("集群 {} 待升级spiderMaster节点数({})与传入ip节点数({})不一致,请确认").format( |
| 191 | + cluster.immute_domain, master_spiders_count, len(spider_master_ip_list) |
| 192 | + ) |
| 193 | + error_msgs.append(error_msg) |
| 194 | + |
| 195 | + slave_spiders_count = cluster.proxyinstance_set.filter( |
| 196 | + tendbclusterspiderext__spider_role=TenDBClusterSpiderRole.SPIDER_SLAVE |
| 197 | + ).count() |
| 198 | + if slave_spiders_count > 0 and len(spider_slave_ip_list) != slave_spiders_count: |
| 199 | + error_msg = _("集群 {} 待升级spiderSlave节点数({})与传入ip节点数({})不一致,请确认").format( |
| 200 | + cluster.immute_domain, slave_spiders_count, len(spider_slave_ip_list) |
| 201 | + ) |
| 202 | + error_msgs.append(error_msg) |
| 203 | + |
| 204 | + return error_msgs |
| 205 | + |
| 206 | + def pre_check_local_upgrade_cross_major_version(self): |
| 207 | + """ |
| 208 | + 检查本地升级时spider实例之间是否存在跨主版本 |
| 209 | +
|
| 210 | + 校验逻辑: |
| 211 | + 1. 仅在本地升级场景(upgrade_local=True)下进行检查 |
| 212 | + 2. 遍历所有待升级的集群信息 |
| 213 | + 3. 获取每个集群的所有spider实例版本 |
| 214 | + 4. 比较最大版本和最小版本是否跨主版本 |
| 215 | + 5. 如果发现跨主版本,记录错误信息 |
| 216 | +
|
| 217 | + 返回: |
| 218 | + - list: 错误信息列表,如果没有错误则返回空列表 |
| 219 | + """ |
| 220 | + error_msgs = [] |
| 221 | + |
| 222 | + # 仅在本地升级场景下进行检查 |
| 223 | + if not self.data.get("upgrade_local", False): |
| 224 | + return error_msgs |
| 225 | + |
| 226 | + for info in self.data["infos"]: |
| 227 | + cluster_id = info["cluster_id"] |
| 228 | + cluster = Cluster.objects.get(id=cluster_id) |
| 229 | + spiders = ProxyInstance.objects.filter(cluster=cluster) |
| 230 | + |
| 231 | + if not spiders.exists(): |
| 232 | + continue |
| 233 | + |
| 234 | + # 收集所有spider实例的版本号 |
| 235 | + version_nums = [tspider_version_parse(spider.version) for spider in spiders] |
| 236 | + |
| 237 | + # 比较最大版本和最小版本是否跨主版本 |
| 238 | + max_version = max(version_nums) |
| 239 | + min_version = min(version_nums) |
| 240 | + |
| 241 | + if spider_cross_major_version(max_version, min_version): |
| 242 | + all_versions = set(spider.version for spider in spiders) |
| 243 | + error_msg = _("集群 {} 本地升级不允许spider实例之间存在跨主版本,当前存在版本: {}").format( |
| 244 | + cluster.immute_domain, ", ".join(all_versions) |
| 245 | + ) |
| 246 | + error_msgs.append(error_msg) |
| 247 | + |
| 248 | + return error_msgs |
| 249 | + |
122 | 250 | def __call__(self): |
123 | 251 | """ |
124 | 252 | 发起校验,实例函数化 |
125 | 253 |
|
126 | 254 | 执行流程: |
127 | | - 1. 调用pre_check_spider_master_spec_consistency方法检查规格一致性 |
128 | | - 2. 如果发现错误,抛出SpiderRoleFailedException异常 |
129 | | - 3. 如果没有错误,返回None表示校验通过 |
| 255 | + 1. 调用pre_check_spider_spec_consistency方法检查规格一致性 |
| 256 | + 2. 调用pre_check_spider_upgrade_version_compatibility方法检查版本兼容性 |
| 257 | + 3. 调用pre_check_spider_node_count_compatibility方法检查节点数量兼容性 |
| 258 | + 4. 如果发现错误,抛出对应的异常 |
| 259 | + 5. 如果没有错误,返回None表示校验通过 |
130 | 260 |
|
131 | 261 | 异常处理: |
132 | 262 | - 当发现规格不一致时,抛出SpiderRoleFailedException |
133 | | - - 异常消息包含所有发现的规格不一致问题 |
| 263 | + - 当发现版本不兼容时,抛出UpgradeVersionFailedException |
| 264 | + - 异常消息包含所有发现的问题 |
134 | 265 |
|
135 | 266 | 返回: |
136 | 267 | - None: 校验通过 |
137 | | - - 异常: 校验失败时抛出SpiderRoleFailedException |
| 268 | + - 异常: 校验失败时抛出对应异常 |
138 | 269 | """ |
139 | 270 | # 检查spider机器规格一致性(包括spider_master和spider_slave) |
140 | 271 | error_msgs = self.pre_check_spider_spec_consistency() |
141 | 272 | if error_msgs: |
142 | 273 | # 将所有错误信息合并为一个字符串,并抛出异常 |
143 | 274 | raise SpiderRoleFailedException("\n".join(error_msgs)) |
144 | 275 |
|
| 276 | + # 检查spider升级版本兼容性 |
| 277 | + error_msgs = self.pre_check_spider_upgrade_version_compatibility() |
| 278 | + if error_msgs: |
| 279 | + raise UpgradeVersionFailedException("\n".join(error_msgs)) |
| 280 | + |
| 281 | + # 检查spider节点数量兼容性(仅迁移升级场景) |
| 282 | + error_msgs = self.pre_check_spider_node_count_compatibility() |
| 283 | + if error_msgs: |
| 284 | + raise UpgradeVersionFailedException("\n".join(error_msgs)) |
| 285 | + |
| 286 | + # 检查本地升级时是否跨主版本 |
| 287 | + error_msgs = self.pre_check_local_upgrade_cross_major_version() |
| 288 | + if error_msgs: |
| 289 | + raise UpgradeVersionFailedException("\n".join(error_msgs)) |
| 290 | + |
145 | 291 | return None |
0 commit comments