Skip to content

Commit

Permalink
feat: 增加mysql/proxy/spider的机器清理flow TencentBlueKing#7553
Browse files Browse the repository at this point in the history
  • Loading branch information
yksitu committed Oct 28, 2024
1 parent 979d722 commit 6639005
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 2 deletions.
34 changes: 33 additions & 1 deletion dbm-ui/backend/db_meta/api/machine/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
import logging
from typing import List, Optional

from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from django.db.models import Q

from backend.components import CCApi
from backend.db_meta import request_validator
from backend.db_meta.enums import MachineTypeAccessLayerMap, machine_type_to_cluster_type
from backend.db_meta.models import BKCity, Machine
from backend.db_meta.models import BKCity, Machine, ProxyInstance, StorageInstance, StorageInstanceTuple
from backend.flow.utils.cc_manage import CcManage

logger = logging.getLogger("root")
Expand Down Expand Up @@ -172,3 +174,33 @@ def update_system_info(bk_cloud_id: int, machines: Optional[List] = None):
Machine.objects.filter(ip=machine["ip"], bk_cloud_id=bk_cloud_id).update(
system_info=machine["system_info"]
)


@transaction.atomic
def clear_info_for_machine(machines: Optional[List]):
"""
根据machine信息回收机器相关信息
"""
for m in machines:
try:
machine = Machine.objects.get(ip=m["ip"], bk_cloud_id=m["bk_cloud_id"])
except ObjectDoesNotExist:
logger.warning(f"the machine [{m['bk_cloud_id']}:{m['ip']}] not exist ")
continue

proxys = ProxyInstance.objects.filter(machine=machine)
storages = StorageInstance.objects.filter(machine=machine)

# 清理proxy相关信息
for p in proxys:
p.tendbclusterspiderext.delete()
p.delete(keep_parents=True)

# 清理storage相关信息
for s in storages:
for info in StorageInstanceTuple.objects.filter(Q(ejector="Alice") | Q(receiver=s)):
# 先删除额外关联信息,否则会报ProtectedError 异常
info.tendbclusterstorageset.delete()
info.delete()
s.delete(keep_parents=True)
machine.delete(keep_parents=True)
3 changes: 3 additions & 0 deletions dbm-ui/backend/flow/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,9 @@ class TruncateDataTypeEnum(str, StructuredEnum):
# sqlserver自定义系统账号列表
SQLSERVER_CUSTOM_SYS_USER = [MSSQL_EXPORTER, MSSQL_ADMIN, MSSQL_DBHA, MSSQL_DRS, "sa"]

# window系统job账号
WINDOW_SYSTEM_JOB_USER = "system"

# tbinlogdumper连接kafka的global config的定义
TBINLOGDUMPER_KAFKA_GLOBAL_CONF = {
"sasl.mechanisms": "SCRAM-SHA-512",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
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.
"""

import logging.config
from dataclasses import asdict
from typing import Dict, Optional

from django.utils.translation import ugettext as _

from backend.flow.engine.bamboo.scene.common.builder import Builder
from backend.flow.plugins.components.collections.common.exec_clear_machine import ClearMachineScriptComponent
from backend.flow.plugins.components.collections.mysql.mysql_db_meta import MySQLDBMetaComponent
from backend.flow.utils.mysql.mysql_act_dataclass import DBMetaOPKwargs
from backend.flow.utils.mysql.mysql_db_meta import MySQLDBMeta

logger = logging.getLogger("flow")


class ClearMysqlMachineFlow(object):
"""
构建清理mysql/proxy/spider机器的流程
兼容跨云区域的执行
"""

def __init__(self, root_id: str, data: Optional[Dict]):
"""
@param root_id : 任务流程定义的root_id
@param data : 单据传递参数
"""
self.root_id = root_id
self.data = data

def run_flow(self):
"""
定义清理机器的执行流程
执行逻辑:
1: 清理和机器相关的dbm元数据
2: 清理机器
"""
# 定义主流程
main_pipeline = Builder(root_id=self.root_id, data=self.data)

main_pipeline.add_act(
act_name=_("清理机器cmdb元数据"),
act_component_code=MySQLDBMetaComponent.code,
kwargs=asdict(DBMetaOPKwargs(db_meta_class_func=MySQLDBMeta.clear_machines.__name__)),
)

main_pipeline.add_act(
act_name=_("清理机器"),
act_component_code=ClearMachineScriptComponent.code,
kwargs={"exec_ips": self.data["clear_hosts"]},
)

main_pipeline.run_pipeline()
8 changes: 8 additions & 0 deletions dbm-ui/backend/flow/engine/controller/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

from backend.db_meta.enums import ClusterType
from backend.flow.engine.bamboo.scene.cloud.mysql_machine_clear_flow import ClearMysqlMachineFlow
from backend.flow.engine.bamboo.scene.common.download_dbactor import DownloadDbactorFlow
from backend.flow.engine.bamboo.scene.common.download_file import DownloadFileFlow
from backend.flow.engine.bamboo.scene.common.transfer_cluster_to_other_biz import TransferMySQLClusterToOtherBizFlow
Expand Down Expand Up @@ -699,3 +700,10 @@ def non_standby_slaves_destroy_scene(self):
"""
flow = DestroyNonStanbySlaveMySQLFlow(root_id=self.root_id, ticket_data=self.ticket_data)
flow.destroy()

def mysql_machine_clear_scene(self):
"""
清理mysql机器
"""
flow = ClearMysqlMachineFlow(root_id=self.root_id, data=self.ticket_data)
flow.run_flow()
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
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.
"""

import logging

from django.utils.translation import ugettext as _
from pipeline.component_framework.component import Component

from backend import env
from backend.components import JobApi
from backend.flow.models import FlowNode
from backend.flow.plugins.components.collections.common.base_service import BkJobService
from backend.flow.utils.clear_machine_script import (
db_type_account_user_map,
db_type_script_map,
os_script_language_map,
)
from backend.utils.string import base64_encode

logger = logging.getLogger("json")


class ClearMachineScriptService(BkJobService):
"""
根据db-actuator组件,绑定fast_execute_script api接口访问。
同时支持跨云管理
"""

def _execute(self, data, parent_data) -> bool:
"""
执行fast_execute_script脚本
global_data 单据全局变量,格式字典
trans_data 单据上下文
kwargs 字典传入格式:
{
root_id: db-actuator任务必须参数,做录入日志平台的条件
node_id: db-actuator任务必须参数,做录入日志平台的条件
node_name: db-actuator任务必须参数,做录入日志平台的条件
}
"""
global_data = data.get_one_of_inputs("global_data")
kwargs = data.get_one_of_inputs("kwargs")

root_id = kwargs["root_id"]
node_name = kwargs["node_name"]
node_id = kwargs["node_id"]
exec_ips = kwargs["exec_ips"]
if not exec_ips:
self.log_error(_("该节点获取到执行ip信息为空,请联系系统管理员{}").format(exec_ips))
return False

# 更新节点信息
FlowNode.objects.filter(root_id=root_id, node_id=node_id).update(hosts=exec_ips)

body = {
"timeout": kwargs.get("job_timeout", 3600),
"account_alias": db_type_account_user_map[global_data["db_type"]],
"bk_biz_id": env.JOB_BLUEKING_BIZ_ID,
"task_name": f"DBM_{node_name}_{node_id}",
"script_content": base64_encode(db_type_script_map[global_data["db_type"]]),
"script_language": os_script_language_map[global_data["os_name"]],
"target_server": {"ip_list": exec_ips},
}
self.log_debug("[{}] ready start task with body {}".format(node_name, body))

resp = JobApi.fast_execute_script(body, raw=True)
self.log_debug(f"{node_name} fast execute script response: {resp}")
self.log_info(f"job url:{env.BK_JOB_URL}/api_execute/{resp['data']['job_instance_id']}")

# 传入调用结果,并单调监听任务状态
data.outputs.ext_result = resp
data.outputs.exec_ips = exec_ips
return True


class ClearMachineScriptComponent(Component):
name = __name__
code = "common_clear_machine_execute"
bound_service = ClearMachineScriptService
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ def _exec_create_node(self, cluster: Cluster, user: str, passwd: str, spider_ip:
).format(tag, user, passwd, spider_ip, spider_port)

rpc_params["cmds"] = cmds + [sql] + ["TDBCTL FLUSH ROUTING"]
self.log_info(f"exec add-node cmds:[{rpc_params['cmds']}]")
res = DRSApi.rpc(rpc_params)

if res[0]["error_msg"]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def _exec_drop_routing(self, cluster: Cluster, spider: ProxyInstance):
f"TDBCTL DROP NODE IF EXISTS {server_name}",
"TDBCTL FLUSH ROUTING",
]
self.log_info(f"exec drop node cmds: [{exec_sql}]")
rpc_params["cmds"] = exec_sql
res = DRSApi.rpc(rpc_params)
if res[0]["error_msg"]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from backend import env
from backend.components import JobApi
from backend.flow.consts import WINDOW_SYSTEM_JOB_USER
from backend.flow.models import FlowNode
from backend.flow.plugins.components.collections.common.base_service import BkJobService
from backend.flow.utils.script_template import sqlserver_actuator_template
Expand Down Expand Up @@ -95,7 +96,7 @@ def _execute(self, data, parent_data) -> bool:

body = {
"timeout": kwargs.get("job_timeout", 3600),
"account_alias": "system",
"account_alias": WINDOW_SYSTEM_JOB_USER,
"is_param_sensitive": 1,
"bk_biz_id": env.JOB_BLUEKING_BIZ_ID,
"task_name": f"DBM_{node_name}_{node_id}",
Expand Down
2 changes: 2 additions & 0 deletions dbm-ui/backend/flow/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
MongoRestoreApiView,
MultiReplicasetInstallApiView,
)
from backend.flow.views.mysql import MysqlMachineClearApiView
from backend.flow.views.mysql_add_slave import AddMysqlSlaveSceneApiView
from backend.flow.views.mysql_add_slave_remote import AddMysqlSlaveRemoteSceneApiView
from backend.flow.views.mysql_checksum import MysqlChecksumSceneApiView
Expand Down Expand Up @@ -455,6 +456,7 @@
url(r"^scene/fake_install_pulsar$", FakeInstallPulsarSceneApiView.as_view()),
url(r"^scene/import_resource_init$", ImportResourceInitStepApiView.as_view()),
url("^scene/mysql_data_migrate$", MysqlDataMigrateSceneApiView.as_view()),
url("^scene/mysql_machine_clear$", MysqlMachineClearApiView.as_view()),
# spider
url(r"^scene/add_spider_mnt$", AddSpiderMNTSceneApiView.as_view()),
url(r"^scene/install_tendb_cluster$", InstallSpiderClusterSceneApiView.as_view()),
Expand Down
70 changes: 70 additions & 0 deletions dbm-ui/backend/flow/utils/clear_machine_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
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 backend.configuration.constants import DBType
from backend.flow.consts import DBA_ROOT_USER, WINDOW_SYSTEM_JOB_USER

os_script_language_map = {"linux": 1, "window": 5}

mysql_clear_machine_script = """
echo "clear mysql crontab...."
crontab -u mysql -r
echo "crontab completed"
echo "killing -9 mysql process ...."
ps uax | grep mysql-proxy | grep -v grep | awk -F ' ' '{print $2}' | xargs -i kill -9 {}
ps uax | grep mysql-crond | grep -v grep | awk -F ' ' '{print $2}' | xargs -i kill -9 {}
ps uax | grep mysqld | grep -v grep | awk -F ' ' '{print $2}' | xargs -i kill -9 {}
ps uax | grep exporter | grep -v grep | awk -F ' ' '{print $2}' | xargs -i kill -9 {}
echo "kill completed"
echo "rm home-mysql-dir ...."
if [ -d "/home/mysql" ]; then
rm -rf /home/mysql/*
fi
echo "rm /home/mysql dir completed"
echo "rm data-dir ...."
if [ -d "/data" ]; then
rm -rf /data/backup_stm/
rm -rf /data/install/
rm -rf /data/dbha/
rm -rf /data/dbbak/
rm -rf /data/mysqldata/
rm -rf /data/mysqllog/
rm -rf /data/mysql-proxy/
rm -rf /data/idip_cache/
fi
echo "rm data-dir completed"
echo "rm data1-dir ...."
if [ -d "/data1" ]; then
rm -rf /data1/mysqldata/
rm -rf /data1/mysqllog/
rm -rf /data1/dbbak/
rm -rf /data1/dbha/
fi
echo "rm data1-dir completed"
"""

sqlserver_clear_machine_script = """
echo 1
"""


db_type_script_map = {
DBType.MySQL.value: mysql_clear_machine_script,
DBType.Sqlserver.value: sqlserver_clear_machine_script,
}

db_type_account_user_map = {
DBType.MySQL.value: DBA_ROOT_USER,
DBType.Sqlserver.value: WINDOW_SYSTEM_JOB_USER,
}
6 changes: 6 additions & 0 deletions dbm-ui/backend/flow/utils/mysql/mysql_db_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,3 +1077,9 @@ def update_cluster_module(self):
with atomic():
for cluster_id in self.cluster["cluster_ids"]:
Cluster.objects.filter(id=cluster_id).update(db_module_id=new_module_id, major_version=major_version)

def clear_machines(self):
"""
清理机器信息
"""
api.machine.clear_info_for_machine(machines=self.ticket_data["clear_hosts"])
31 changes: 31 additions & 0 deletions dbm-ui/backend/flow/views/mysql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
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.
"""
import logging

from rest_framework.response import Response

from backend.flow.engine.controller.mysql import MySQLController
from backend.flow.views.base import FlowTestView
from backend.utils.basic import generate_root_id

logger = logging.getLogger("root")


class MysqlMachineClearApiView(FlowTestView):
"""
api: /apis/v1/flow/scene/mysql_machine_clear
params:
"""

def post(self, request):
root_id = generate_root_id()
flow = MySQLController(root_id=root_id, ticket_data=request.data)
flow.mysql_machine_clear_scene()
return Response({"root_id": root_id})

0 comments on commit 6639005

Please sign in to comment.