diff --git a/dbm-ui/backend/db_meta/flatten/proxy_instance.py b/dbm-ui/backend/db_meta/flatten/proxy_instance.py index 8f521e3296..a610d5e5d3 100644 --- a/dbm-ui/backend/db_meta/flatten/proxy_instance.py +++ b/dbm-ui/backend/db_meta/flatten/proxy_instance.py @@ -109,6 +109,7 @@ def proxy_instance(proxies: QuerySet) -> List[Dict]: info["bind_entry"] = dict(bind_entry) for cluster in ins.cluster.all(): info["cluster"] = cluster.immute_domain + info["cluster_id"] = cluster.id # 只取第一个即可退出 break diff --git a/dbm-ui/backend/db_meta/flatten/storage_instance.py b/dbm-ui/backend/db_meta/flatten/storage_instance.py index 48a12e20e0..f45c878c2e 100644 --- a/dbm-ui/backend/db_meta/flatten/storage_instance.py +++ b/dbm-ui/backend/db_meta/flatten/storage_instance.py @@ -142,6 +142,7 @@ def storage_instance(storages: QuerySet) -> List[Dict]: for cluster in ins.cluster.all(): info["cluster"] = cluster.immute_domain + info["cluster_id"] = cluster.id info["tbinlogdumpers"] = [ {"ip": dumper.ip, "port": dumper.listen_port} for dumper in dumper_infos.get(cluster.id, {}).get(ins.machine.ip, []) diff --git a/dbm-ui/backend/db_services/redis/redis_dts/migrate_cluster_password.py b/dbm-ui/backend/db_services/redis/redis_dts/migrate_cluster_password.py new file mode 100644 index 0000000000..1a950a8203 --- /dev/null +++ b/dbm-ui/backend/db_services/redis/redis_dts/migrate_cluster_password.py @@ -0,0 +1,82 @@ +# -*- 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. +""" + +import base64 + +from django.utils.translation import ugettext as _ + +from backend.components import DBConfigApi, MySQLPrivManagerApi +from backend.db_meta.models import Cluster +from backend.flow.consts import DBM_JOB, DEFAULT_INSTANCE, MySQLPrivComponent, UserName +from backend.flow.utils.base.payload_handler import PayloadHandler + + +def decode_password_ret(data) -> dict: + ret = {"redis_password": "", "redis_proxy_admin_password": "", "redis_proxy_password": ""} + for item in data["items"]: + if ( + item["username"] == UserName.REDIS_DEFAULT.value + and item["component"] == MySQLPrivComponent.REDIS_PROXY_ADMIN.value + ): + ret["redis_proxy_admin_password"] = base64.b64decode(item["password"]).decode("utf-8") + elif ( + item["username"] == UserName.REDIS_DEFAULT.value + and item["component"] == MySQLPrivComponent.REDIS_PROXY.value + ): + ret["redis_proxy_password"] = base64.b64decode(item["password"]).decode("utf-8") + elif item["username"] == UserName.REDIS_DEFAULT.value and item["component"] == MySQLPrivComponent.REDIS.value: + ret["redis_password"] = base64.b64decode(item["password"]).decode("utf-8") + return ret + + +def redis_migate_cluster_password(cluster: Cluster): + # cluster_port = cluster.proxyinstance_set.first().port + cluster_port = 0 + query_params = { + "instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}], + "users": [ + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value}, + ], + } + data = MySQLPrivManagerApi.get_password(query_params) + ret = decode_password_ret(data) + if ret["redis_password"] and ret["redis_proxy_password"] and ret["redis_proxy_admin_password"]: + print(_("cluster:{} 密码已经正确存储").format(cluster.immute_domain)) + return + cluster_port = cluster.proxyinstance_set.first().port + query_params = { + "instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}], + "users": [ + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value}, + ], + } + data = MySQLPrivManagerApi.get_password(query_params) + ret = decode_password_ret(data) + if ret["redis_password"] and ret["redis_proxy_password"] and ret["redis_proxy_admin_password"]: + print(_("cluster:{} 密码已存储port不正确,重新存储").format(cluster.immute_domain)) + PayloadHandler.redis_save_password_by_cluster( + cluster, ret["redis_password"], ret["redis_proxy_password"], ret["redis_proxy_admin_password"] + ) + PayloadHandler.redis_delete_cluster_password( + cluster_id=cluster.id, cluster_port=cluster_port, bk_cloud_id=cluster.bk_cloud_id + ) + return + # 从 dbconfig 中获取密码 + conf_passwd = PayloadHandler.redis_get_cluster_pass_from_dbconfig(cluster) + if not conf_passwd["redis_password"].startswith("{{") and not conf_passwd["redis_proxy_password"].startswith("{{"): + print(_("cluster:{} 密码从dbconfig中迁移到密码服务中").format(cluster.immute_domain)) + PayloadHandler.redis_save_password_by_cluster(cluster, conf_passwd, conf_passwd, conf_passwd) + return + raise Exception(_("cluster:{} 在 dbconfig和密码服务中均不存在").format(cluster.immute_domain)) diff --git a/dbm-ui/backend/flow/utils/base/payload_handler.py b/dbm-ui/backend/flow/utils/base/payload_handler.py index be31d5d33e..44afcd965b 100644 --- a/dbm-ui/backend/flow/utils/base/payload_handler.py +++ b/dbm-ui/backend/flow/utils/base/payload_handler.py @@ -218,7 +218,8 @@ def redis_get_cluster_password(cluster: Cluster): - 优先从密码服务中获取 - 如果密码服务为空,则从dbconfig中获取 """ - cluster_port = cluster.proxyinstance_set.first().port + # cluster_port 先全部统一设置为 0,便于DBHA获取密码 + cluster_port = 0 query_params = { "instances": [{"ip": str(cluster.id), "port": cluster_port, "bk_cloud_id": cluster.bk_cloud_id}], "users": [ @@ -282,6 +283,8 @@ def redis_save_cluster_password( """ 存储redis集群的密码到密码服务 """ + # cluster_port 先全部统一设置为 0,便于DBHA获取密码 + cluster_port = 0 query_params = { "instances": [{"ip": str(cluster_id), "port": cluster_port, "bk_cloud_id": bk_cloud_id}], "username": UserName.REDIS_DEFAULT.value, @@ -315,10 +318,9 @@ def redis_save_password_by_cluster( redis_proxy_password: str = "", redis_proxy_admin_password: str = "", ): - cluster_port = cluster.proxyinstance_set.first().port return PayloadHandler.redis_save_cluster_password( cluster.id, - cluster_port, + 0, cluster.bk_cloud_id, redis_password, redis_proxy_password, @@ -330,10 +332,9 @@ def redis_save_password_by_cluster_id( cluster_id: int, redis_password: str = "", redis_proxy_password: str = "", redis_proxy_admin_password: str = "" ): cluster = Cluster.objects.get(id=cluster_id) - cluster_port = cluster.proxyinstance_set.first().port return PayloadHandler.redis_save_cluster_password( cluster.id, - cluster_port, + 0, cluster.bk_cloud_id, redis_password, redis_proxy_password, @@ -348,16 +349,45 @@ def redis_save_password_by_domain( redis_proxy_admin_password: str = "", ): cluster = Cluster.objects.get(immute_domain=immute_domain) - cluster_port = cluster.proxyinstance_set.first().port return PayloadHandler.redis_save_cluster_password( cluster.id, - cluster_port, + 0, cluster.bk_cloud_id, redis_password, redis_proxy_password, redis_proxy_admin_password, ) + @staticmethod + def redis_delete_cluster_password(cluster_id: int, cluster_port: int, bk_cloud_id: int): + """ + 删除redis集群的密码 + """ + delete_params = { + "instances": [{"ip": str(cluster_id), "port": cluster_port, "bk_cloud_id": bk_cloud_id}], + "users": [ + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY_ADMIN.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS_PROXY.value}, + {"username": UserName.REDIS_DEFAULT.value, "component": MySQLPrivComponent.REDIS.value}, + ], + } + MySQLPrivManagerApi.delete_password(delete_params) + + @staticmethod + def redis_delete_password_by_cluster(cluster: Cluster): + """ + 根据cluster对象,删除redis集群的密码 + """ + PayloadHandler.redis_delete_cluster_password(cluster.id, 0, cluster.bk_cloud_id) + + @staticmethod + def redis_delete_password_by_immute_domain(immute_domain: str): + """ + 根据域名删除redis集群的密码 + """ + cluster = Cluster.objects.get(immute_domain=immute_domain) + PayloadHandler.redis_delete_cluster_password(cluster.id, 0, cluster.bk_cloud_id) + @staticmethod def redis_get_os_account() -> dict: """