diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_cluster_topo.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_cluster_topo.py deleted file mode 100644 index adb55d14b8..0000000000 --- a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_cluster_topo.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -""" -TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. -Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at https://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" -from django.utils.translation import ugettext as _ - -from backend.db_meta.enums import ClusterType, InstanceInnerRole, InstanceRole, MachineType -from backend.db_meta.models import Cluster -from backend.db_report.enums import MetaCheckSubType -from backend.db_report.models import MetaCheckReport - - -def check_cluster_topo(): - _check_tendbsingle_topo() - _check_tendbha_topo() - _check_tendbcluster_topo() - - -def _check_tendbsingle_topo(): - """ - 有且只有一个存储实例 - """ - for c in Cluster.objects.filter(cluster_type=ClusterType.TenDBSingle): - messages = [] - if c.proxyinstance_set.exists(): - messages.append(_("有 {} 个接入层实例".format(c.proxyinstance_set.count()))) - - if c.storageinstance_set.count() != 1: - messages.append(_("有 {} 个存储层实例".format(c.storageinstance_set.count()))) - - ins = c.storageinstance_set.get() - if not ( - ins.machine.machine_type == MachineType.SINGLE.value - and ins.instance_role == InstanceRole.ORPHAN.value - and ins.instance_inner_role == InstanceInnerRole.ORPHAN.value - ): - messages.append( - _( - "实例 {} ({}-{}-{}) 与集群类型不匹配".format( - ins.ip_port, ins.machine.machine_type, ins.instance_role, ins.instance_inner_role - ) - ) - ) - - if messages: - MetaCheckReport.objects.create( - bk_biz_id=c.bk_biz_id, - bk_cloud_id=c.bk_cloud_id, - cluster=c.immute_domain, - cluster_type=ClusterType.TenDBSingle, - status=False, - msg=", ".join(messages), - subtype=MetaCheckSubType.ClusterTopo.value, - ) - - -def _check_tendbha_topo(): - """ - 1. 至少 2 个 proxy - 2. 1 个 master - 3. 至少 1 个 slave - """ - Cluster.objects.filter(cluster_type=ClusterType.TenDBHA) - - -def _check_tendbcluster_topo(): - Cluster.objects.filter(cluster_type=ClusterType.TenDBCluster) diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_instance_belong.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_instance_belong.py deleted file mode 100644 index 626ac33195..0000000000 --- a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_instance_belong.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -""" -TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. -Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at https://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" - -from django.db.models import Count, Q, QuerySet -from django.utils.translation import ugettext_lazy as _ - -from backend.db_meta.models import ProxyInstance, StorageInstance -from backend.db_report.enums import MetaCheckSubType -from backend.db_report.models import MetaCheckReport - - -def check_instance_belong(): - """ - 所有实例都应该属于唯一一个集群 - """ - _instance_belong(StorageInstance.objects.all()) - _instance_belong(ProxyInstance.objects.all()) - - -def _instance_belong(qs: QuerySet): - for ins in qs.annotate(cluster_count=Count("cluster")).filter(~Q(cluster_count=1)): - if ins.cluster.exists(): # 大于 1 个集群 - msg = _("{} 属于 {} 个集群".format(ins.ip_port, ins.cluster.count())) # ToDo 详情 - else: # 不属于任何集群 - msg = _("{} 不属于任何集群".format(ins.ip_port)) - - MetaCheckReport.objects.create( - bk_biz_id=ins.bk_biz_id, - bk_cloud_id=ins.machine.bk_cloud_id, - ip=ins.machine.ip, - port=ins.port, - cluster_type=ins.cluster_type, - machine_type=ins.machine.machine_type, - status=False, - msg=msg, - subtype=MetaCheckSubType.InstanceBelong.value, - ) diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_replicate_role.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_replicate_role.py deleted file mode 100644 index b50df93486..0000000000 --- a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/check_replicate_role.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -""" -TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. -Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. -Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. -You may obtain a copy of the License at https://opensource.org/licenses/MIT -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. -""" -from django.core.exceptions import ObjectDoesNotExist -from django.utils.translation import ugettext_lazy as _ - -from backend.db_meta.enums import InstanceInnerRole -from backend.db_meta.models import StorageInstanceTuple -from backend.db_report.enums import MetaCheckSubType -from backend.db_report.models import MetaCheckReport - - -def check_replicate_role(): - """ - ejector 只能是 master, repeater; 即不能是 slave - receiver 只能是 slave, repeater; 即不能是 master - """ - for bad_ejector_tuple in StorageInstanceTuple.objects.filter( - ejector__instance_inner_role=InstanceInnerRole.SLAVE.value - ): - ejector = bad_ejector_tuple.ejector - try: - MetaCheckReport.objects.create( - bk_biz_id=ejector.bk_biz_id, - bk_cloud_id=ejector.machine.bk_cloud_id, - ip=ejector.machine.ip, - port=ejector.port, - cluster=ejector.cluster.get().immute_domain, - cluster_type=ejector.cluster_type, - machine_type=ejector.machine.machine_type, - status=False, - msg=_("{} {} 不能作为同步 ejector".format(ejector.ip_port, ejector.instance_inner_role)), - subtype=MetaCheckSubType.ReplicateRole.value, - ) - except ObjectDoesNotExist: # 忽略实例没有集群关系的异常, instance-belong 会发现这个错误 - pass - - for bad_receiver_tuple in StorageInstanceTuple.objects.filter( - receiver__instance_inner_role=InstanceInnerRole.MASTER.value - ): - receiver = bad_receiver_tuple.ejector - try: - MetaCheckReport.objects.create( - bk_biz_id=receiver.bk_biz_id, - bk_cloud_id=receiver.machine.bk_cloud_id, - ip=receiver.machine.ip, - port=receiver.port, - cluster=receiver.cluster.get().immute_domain, - cluster_type=receiver.cluster_type, - machine_type=receiver.machine.machine_type, - status=False, - msg=_("{} {} 不能作为同步 receiver".format(receiver.ip_port, receiver.instance_inner_role)), - subtype=MetaCheckSubType.ReplicateRole.value, - ) - except ObjectDoesNotExist: # 忽略实例没有集群关系的异常, instance-belong 会发现这个错误 - pass diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/__init__.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/__init__.py new file mode 100644 index 0000000000..aa5085c628 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/check_response.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/check_response.py new file mode 100644 index 0000000000..e750f031e4 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/check_response.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import Optional, Union + +from backend.db_meta.models import ProxyInstance, StorageInstance +from backend.db_report.enums import MetaCheckSubType + + +class CheckResponse: + def __init__( + self, + msg: str, + check_subtype: MetaCheckSubType, + instance: Optional[Union[StorageInstance, ProxyInstance]] = None, + ): + self.msg = msg + self.check_subtype = check_subtype + self.instance = instance diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/decorator.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/decorator.py new file mode 100644 index 0000000000..16ecd06a7e --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/decorator.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_report.models import MetaCheckReport + + +def checker_wrapper(checker): + def wrapper(c: Cluster) -> List[MetaCheckReport]: + out_reports = [] + check_response: List[CheckResponse] = checker(c) + if not check_response: + return out_reports + + for cr in check_response: + out_report = MetaCheckReport( + subtype=cr.check_subtype, + bk_biz_id=c.bk_biz_id, + bk_cloud_id=c.bk_cloud_id, + status=False, + msg=cr.msg, + cluster=c.immute_domain, + cluster_type=c.cluster_type, + creator="system", + updater="system", + # create_at=timezone.localtime(timezone.now()), + # update_at=timezone.localtime(timezone.now()), + ip="0.0.0.0", + port=0, + machine_type="", + ) + if cr.instance: + out_report.ip = cr.instance.machine.ip + out_report.port = cr.instance.port + out_report.machine_type = cr.instance.machine_type + + out_reports.append(out_report) + + return out_reports + + return wrapper diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/__init__.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/__init__.py new file mode 100644 index 0000000000..d7210a4422 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/__init__.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from .check import health_check diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/access_relate.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/access_relate.py new file mode 100644 index 0000000000..6eedd13129 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/access_relate.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from django.utils.translation import ugettext_lazy as _ + +from backend.db_meta.enums import InstanceInnerRole +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.decorator import checker_wrapper +from backend.db_report.enums import MetaCheckSubType + + +@checker_wrapper +def _cluster_proxy_access_master( + c: Cluster, +) -> List[CheckResponse]: + """ + proxy 必须且只能关联到 master + """ + bad = [] + for pi in c.proxyinstance_set.all(): + for si in pi.storageinstance.all(): + if si.instance_inner_role != InstanceInnerRole.MASTER: + bad.append( + CheckResponse( + msg=_("proxy 关联到 {}: {}".format(si.instance_inner_role, si.ip_port)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=pi, + ) + ) + + return bad diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/check.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/check.py new file mode 100644 index 0000000000..bce1148d18 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/check.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from backend.db_meta.enums import ClusterType +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.tendbha.access_relate import ( + _cluster_proxy_access_master, +) +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.tendbha.entry_bind import ( + _cluster_entry_real_bind, + _cluster_master_entry_on_proxy, + _cluster_master_entry_on_storage, +) +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.tendbha.replicate import ( + _cluster_master_as_ejector, + _cluster_replicate_out, + _cluster_slave_as_receiver, +) +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.tendbha.status import ( + _cluster_master_entry_count, + _cluster_master_status, + _cluster_one_master, + _cluster_one_standby_slave, + _cluster_proxy_count, + _cluster_standby_slave_status, + _cluster_status, +) +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.tendbha.unique_cluster import ( + _cluster_instance_unique_cluster, +) + + +def health_check(cluster_id: int) -> List[CheckResponse]: + """ + 所有检查项应相互独立 + 集群状态正常 + 主入口数 >= 1 + proxy 数 >= 2 + 唯一 master + master 状态正常 + 唯一 standby slave + standby slave 状态正常 + 主入口 bind 的 proxy 必须和集群正常 proxy 数量一致 + 主入口不能 bind 到存储 + ToDo 检查域名真实的 bind 配置 + proxy 只能访问 master + master 只能作为 ejector + slave 只能作为 receiver + 不允许有到集群外部的同步关系 + """ + qs = Cluster.objects.filter(cluster_type=ClusterType.TenDBHA).prefetch_related( + "clusterentry_set__proxyinstance_set", + "clusterentry_set__storageinstance_set", + "proxyinstance_set__storageinstance", + "storageinstance_set__as_receiver__ejector__cluster", + "storageinstance_set__as_ejector__receiver__cluster", + "storageinstance_set__cluster", + "proxyinstance_set__cluster", + ) + cluster_obj = qs.get(id=cluster_id) + + res = [] + + res.extend(_cluster_status(cluster_obj)) + res.extend(_cluster_instance_unique_cluster(cluster_obj)) + res.extend(_cluster_master_entry_count(cluster_obj)) + res.extend(_cluster_proxy_count(cluster_obj)) + res.extend(_cluster_one_master(cluster_obj)) + res.extend(_cluster_master_status(cluster_obj)) + res.extend(_cluster_one_standby_slave(cluster_obj)) + res.extend(_cluster_standby_slave_status(cluster_obj)) + res.extend(_cluster_master_entry_on_proxy(cluster_obj)) + res.extend(_cluster_master_entry_on_storage(cluster_obj)) + res.extend(_cluster_entry_real_bind(cluster_obj)) + res.extend(_cluster_proxy_access_master(cluster_obj)) + res.extend(_cluster_master_as_ejector(cluster_obj)) + res.extend(_cluster_slave_as_receiver(cluster_obj)) + res.extend(_cluster_replicate_out(cluster_obj)) + + return res diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/entry_bind.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/entry_bind.py new file mode 100644 index 0000000000..b98a2d115f --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/entry_bind.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from django.utils.translation import ugettext_lazy as _ + +from backend.db_meta.enums import ClusterEntryRole, ClusterEntryType, InstancePhase, InstanceStatus +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.decorator import checker_wrapper +from backend.db_report.enums import MetaCheckSubType + + +@checker_wrapper +def _cluster_master_entry_on_proxy(c: Cluster) -> List[CheckResponse]: + """ + 主入口 bind 到 proxy 的数量必须和集群正常 proxy 相等 + """ + bad = [] + for cme in c.clusterentry_set.all(): + if cme.role == ClusterEntryRole.MASTER_ENTRY: + cluster_proxy_cnt = 0 + for pi in c.proxyinstance_set.all(): + if pi.status == InstanceStatus.RUNNING and pi.phase == InstancePhase.ONLINE: + cluster_proxy_cnt += 1 + + if cme.proxyinstance_set.count() != cluster_proxy_cnt: + bad.append( + CheckResponse( + msg=_("主访问入口 {} 关联 proxy 和集群 proxy 数量不相等".format(cme.entry)), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ) + + return bad + + +@checker_wrapper +def _cluster_master_entry_on_storage(c: Cluster) -> List[CheckResponse]: + """ + 主入口不能 bind 到存储 + """ + bad = [] + for cme in c.clusterentry_set.all(): + if cme.role == ClusterEntryRole.MASTER_ENTRY: + for si in cme.storageinstance_set.all(): + bad.append( + CheckResponse( + msg=_("主访问入口 {} 关联到存储实例".format(cme.entry)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + return bad + + +@checker_wrapper +def _cluster_entry_real_bind(c: Cluster) -> List[CheckResponse]: + """ + 检查访问入口的真实 bind 关系是否和元数据相符 + """ + bad = [] + for ce in c.clusterentry_set.all(): + if ce.cluster_entry_type == ClusterEntryType.DNS: + if not _cluster_dns_entry_real_bind(c): + bad.append( + CheckResponse( + msg=_(""), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ) + + return bad + + +def _cluster_dns_entry_real_bind(c: Cluster) -> bool: + """ + ToDo dns 真实 bind 检查 + """ + return True diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/replicate.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/replicate.py new file mode 100644 index 0000000000..a3e49b7115 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/replicate.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from django.utils.translation import ugettext_lazy as _ + +from backend.db_meta.enums import InstanceInnerRole +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.decorator import checker_wrapper +from backend.db_report.enums import MetaCheckSubType + + +@checker_wrapper +def _cluster_master_as_ejector(c: Cluster) -> List[CheckResponse]: + """ + master 只能是 ejector + """ + bad = [] + for si in c.storageinstance_set.all(): + if si.instance_inner_role == InstanceInnerRole.MASTER: + for tp in si.as_receiver.all(): + bad.append( + CheckResponse( + msg=_("master 为 receiver 与 {} 有同步关系".format(tp.ejector.ip_port)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + return bad + + +@checker_wrapper +def _cluster_slave_as_receiver(c: Cluster) -> List[CheckResponse]: + """ + slave 只能是 receiver + """ + bad = [] + for si in c.storageinstance_set.all(): + if si.instance_inner_role == InstanceInnerRole.SLAVE: + for tp in si.as_ejector.all(): + bad.append( + CheckResponse( + msg=_("slave 作为 ejector 与 {} 有同步关系".format(tp.receiver.ip_port)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + return bad + + +@checker_wrapper +def _cluster_replicate_out(c: Cluster) -> List[CheckResponse]: + """ + 不能同步到集群外部 + """ + bad = [] + for si in c.storageinstance_set.all(): + for tp in si.as_ejector.all(): + for rc in tp.receiver.cluster.all(): + if rc.id != c.id: + bad.append( + CheckResponse( + msg=_("与外部集群 {} {} 有同步关系".format(rc.immute_domain, tp.receiver.ip_port)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + for tp in si.as_receiver.all(): + for rc in tp.ejector.cluster.all(): + if rc.id != c.id: + bad.append( + CheckResponse( + msg=_("与外部集群 {} {} 有同步关系".format(rc.immute_domain, tp.receiver.ip_port)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + return bad diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/status.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/status.py new file mode 100644 index 0000000000..7fc22daf4e --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/status.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + +from typing import List + +from django.utils.translation import ugettext_lazy as _ + +from backend.db_meta.enums import ClusterEntryRole, ClusterStatus, InstanceInnerRole, InstancePhase, InstanceStatus +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.decorator import checker_wrapper +from backend.db_report.enums import MetaCheckSubType + + +@checker_wrapper +def _cluster_status(c: Cluster) -> List[CheckResponse]: + if c.status != ClusterStatus.NORMAL: + return [ + CheckResponse( + msg=_("集群状态异常: {}".format(c.status)), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ] + + +@checker_wrapper +def _cluster_instance_status(c: Cluster) -> List[CheckResponse]: + bad = [] + for si in c.storageinstance_set.all(): + if si.status != InstanceStatus.RUNNING or si.phase != InstancePhase.ONLINE: + bad.append( + CheckResponse( + msg=_("实例 {} 状态异常: {}, {}".format(si.ip_port, si.status, si.phase)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + for pi in c.proxyinstance_set.all(): + if pi.status != InstanceStatus.RUNNING or pi.phase != InstancePhase.ONLINE: + bad.append( + CheckResponse( + msg=_("实例 {} 状态异常: {}, {}".format(pi.ip_port, pi.status, pi.phase)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=pi, + ) + ) + + return bad + + +@checker_wrapper +def _cluster_master_entry_count(c: Cluster) -> List[CheckResponse]: + """ + 至少 1 个主访问入口 + """ + cnt = 0 + for ce in c.clusterentry_set.all(): + if ce.role == ClusterEntryRole.MASTER_ENTRY: + cnt += 1 + + if cnt <= 0: + return [CheckResponse(msg=_("缺少主访问入口"), check_subtype=MetaCheckSubType.ClusterTopo)] + + +@checker_wrapper +def _cluster_proxy_count(c: Cluster) -> List[CheckResponse]: + """ + 至少 2 个存活的 proxy + """ + cnt = 0 + for pi in c.proxyinstance_set.all(): + if pi.status == InstanceStatus.RUNNING and pi.phase == InstancePhase.ONLINE: + cnt += 1 + + if cnt < 2: + return [CheckResponse(msg=_("正常 proxy 不足 2 个"), check_subtype=MetaCheckSubType.ClusterTopo)] + + +@checker_wrapper +def _cluster_one_master(c: Cluster) -> List[CheckResponse]: + """只能有一个 master""" + m = [] + for si in c.storageinstance_set.all(): + if si.instance_inner_role == InstanceInnerRole.MASTER: + m.append(si) + + if len(m) <= 0: + return [CheckResponse(msg=_("无 master 实例"), check_subtype=MetaCheckSubType.ClusterTopo)] + + if len(m) > 1: + return [ + CheckResponse( + msg=_("master 多余 1 个: {}".format(",".join([ele.ip_port for ele in m]))), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ] + + +@checker_wrapper +def _cluster_master_status( + c: Cluster, +) -> List[CheckResponse]: + """ + master 必须 + status == running + phase == online + is_stand_by = True + """ + cnt = 0 + for si in c.storageinstance_set.all(): + if ( + si.instance_inner_role == InstanceInnerRole.MASTER + and si.status == InstanceStatus.RUNNING + and si.phase == InstancePhase.ONLINE + ): + cnt += 1 + + if cnt <= 0: + return [CheckResponse(msg=_("无正常 master"), check_subtype=MetaCheckSubType.ClusterTopo)] + + +@checker_wrapper +def _cluster_one_standby_slave( + c: Cluster, +) -> List[CheckResponse]: + """ + 只能有一个 standby slave + """ + m = [] + for si in c.storageinstance_set.all(): + if si.instance_inner_role == InstanceInnerRole.SLAVE and si.is_stand_by is True: + m.append(si) + + if len(m) <= 0: + return [CheckResponse(msg=_("无 standby slave"), check_subtype=MetaCheckSubType.ClusterTopo)] + + if len(m) > 1: + return [ + CheckResponse( + msg=_("standby slave 多余 1 个: {}".format(",".join([ele.ip_port for ele in m]))), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ] + + +@checker_wrapper +def _cluster_standby_slave_status( + c: Cluster, +) -> List[CheckResponse]: + """ + standby slave 必须正常 + """ + bad = [] + for si in c.storageinstance_set.all(): + if (si.instance_inner_role == InstanceInnerRole.SLAVE and si.is_stand_by is True) and ( + si.status != InstanceStatus.RUNNING or si.phase != InstancePhase.ONLINE + ): + bad.append(si) + + if bad: + return [ + CheckResponse( + msg=_("standby slave 状态异常: {}".format(",".join([ele.ip_port for ele in bad]))), + check_subtype=MetaCheckSubType.ClusterTopo, + ) + ] diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/unique_cluster.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/unique_cluster.py new file mode 100644 index 0000000000..6744cd46b5 --- /dev/null +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/mysql_cluster_topo/tendbha/unique_cluster.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from typing import List + +from django.utils.translation import ugettext_lazy as _ + +from backend.db_meta.models import Cluster +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.check_response import CheckResponse +from backend.db_periodic_task.local_tasks.db_meta.db_meta_check.mysql_cluster_topo.decorator import checker_wrapper +from backend.db_report.enums import MetaCheckSubType + + +@checker_wrapper +def _cluster_instance_unique_cluster(c: Cluster) -> List[CheckResponse]: + """ + 实例只能属于一个集群 + """ + bad = [] + for si in c.storageinstance_set.all(): + for sc in si.cluster.all(): + if sc.id != c.id: + bad.append( + CheckResponse( + msg=_("实例同时属于另一个集群: {}".format(sc.immute_domain)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=si, + ) + ) + + for pi in c.proxyinstance_set.all(): + for pc in pi.cluster.all(): + if pc.id != c.id: + bad.append( + CheckResponse( + msg=_("实例同时属于另一个集群: {}".format(pc.immute_domain)), + check_subtype=MetaCheckSubType.ClusterTopo, + instance=pi, + ) + ) + + return bad diff --git a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/task.py b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/task.py index e5fbea0557..466255c442 100644 --- a/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/task.py +++ b/dbm-ui/backend/db_periodic_task/local_tasks/db_meta/db_meta_check/task.py @@ -12,11 +12,13 @@ from celery.schedules import crontab +from backend.db_meta.enums import ClusterType +from backend.db_meta.models import Cluster from backend.db_periodic_task.local_tasks.register import register_periodic_task +from backend.db_report.models import MetaCheckReport -from .check_instance_belong import check_instance_belong from .check_redis_instance import check_redis_instance -from .check_replicate_role import check_replicate_role +from .mysql_cluster_topo.tendbha import health_check logger = logging.getLogger("celery") @@ -27,5 +29,11 @@ def db_meta_check_task(): 巡检校验元数据 """ check_redis_instance() - check_instance_belong() - check_replicate_role() + + +@register_periodic_task(run_every=crontab(hour=2, minute=30)) +def tendbha_topo_daily_check(): + for c in Cluster.objects.filter(cluster_type=ClusterType.TenDBHA): + r: MetaCheckReport + for r in health_check(c.id): + r.save() diff --git a/dbm-ui/backend/db_proxy/reverse_api/mysql/impl/list_instance_info.py b/dbm-ui/backend/db_proxy/reverse_api/mysql/impl/list_instance_info.py index a6655519d4..e1a8c9386c 100644 --- a/dbm-ui/backend/db_proxy/reverse_api/mysql/impl/list_instance_info.py +++ b/dbm-ui/backend/db_proxy/reverse_api/mysql/impl/list_instance_info.py @@ -34,7 +34,9 @@ def list_instance_info(bk_cloud_id: int, ip: str, port_list: Optional[List[int]] def list_storageinstance_info(q: Q) -> List: res = [] - for i in StorageInstance.objects.filter(q): + for i in StorageInstance.objects.filter(q).prefetch_related( + "as_ejector__receiver__machine", "as_receiver__ejector__machine", "machine" + ): receivers = [] ejectors = [] for t in i.as_ejector.all(): @@ -71,7 +73,7 @@ def list_storageinstance_info(q: Q) -> List: def list_proxyinstance_info(q: Q) -> List: res = [] - for i in ProxyInstance.objects.filter(q): + for i in ProxyInstance.objects.filter(q).prefetch_related("machine"): res.append( { "ip": i.machine.ip, diff --git a/dbm-ui/backend/db_report/serializers/__init__.py b/dbm-ui/backend/db_report/serializers/__init__.py new file mode 100644 index 0000000000..aa5085c628 --- /dev/null +++ b/dbm-ui/backend/db_report/serializers/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" diff --git a/dbm-ui/backend/db_report/serializers/meta_check_report_serializer.py b/dbm-ui/backend/db_report/serializers/meta_check_report_serializer.py new file mode 100644 index 0000000000..37e1436a30 --- /dev/null +++ b/dbm-ui/backend/db_report/serializers/meta_check_report_serializer.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. +Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at https://opensource.org/licenses/MIT +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +from rest_framework import serializers + +from backend.db_report.models import MetaCheckReport + + +class MetaCheckReportSerializer(serializers.ModelSerializer): + class Meta: + model = MetaCheckReport + fields = "__all__"