diff --git a/dbm-ui/frontend/src/components/instance-selector/Index.vue b/dbm-ui/frontend/src/components/instance-selector/Index.vue index 35229067e3..9ef65f1507 100644 --- a/dbm-ui/frontend/src/components/instance-selector/Index.vue +++ b/dbm-ui/frontend/src/components/instance-selector/Index.vue @@ -106,22 +106,44 @@ bk_cloud_name: string; bk_host_id: number; cluster_id: number; - cluster_name: string; + cluster_name?: string; cluster_type: string; + create_at: string; db_module_id: number; db_module_name: string; + host_info: any; id: number; + name: string; + instance_address: string; + instance_role: string; ip: string; port: number; - instance_address: string; status?: string; - host_info?: any; + machine_type: string; master_domain: string; - related_instances?: { - instance: string; + related_clusters: { + id: number; + name: string; + master_domain: string; + immute_domain: string; + cluster_type: string; + }[]; + related_instances: { + cluster_id: number; + ip: string; + name: string; + phase: string; + port: number; status: string; + instance: string; + bk_biz_id: number; + bk_cloud_id: number; + bk_host_id: number; + bk_instance_id: number; + admin_port: number; }[]; spec_config?: TendbclusterMachineModel['spec_config']; + spec_id?: number; role: string; } @@ -201,7 +223,7 @@ getSqlServerInstanceList as getSqlServerSingleInstanceList, } from '@services/source/sqlserverSingleCluster'; import { getTendbclusterInstanceList, getTendbclusterMachineList } from '@services/source/tendbcluster'; - import { getTendbhaInstanceList } from '@services/source/tendbha'; + import { getTendbhaInstanceList, getTendbhaMachineList } from '@services/source/tendbha'; import { getTendbsingleInstanceList } from '@services/source/tendbsingle'; import { ClusterTypes } from '@common/const'; @@ -217,6 +239,7 @@ import SqlServerContent from './components/sqlserver/Index.vue'; import TendbClusterContent from './components/tendb-cluster/Index.vue'; import TendbClusterHostContent from './components/tendb-cluster-host/Index.vue'; + import TendbhaHostContent from './components/tendb-ha-host/Index.vue'; export type TableSetting = ReturnType; @@ -511,6 +534,51 @@ content: ManualInputContent, }, ], + TendbhaHost: [ + { + id: 'TendbhaHost', + name: t('主库主机'), + topoConfig: { + getTopoList: getMysqlClusterList, + }, + tableConfig: { + getTableList: getTendbhaMachineList, + firsrColumn: { + label: t('主库主机'), + field: 'ip', + role: 'master', + }, + columnsChecked: ['ip', 'related_instances', 'cloud_area', 'alive', 'host_name', 'os_name'], + }, + previewConfig: { + displayKey: 'ip', + }, + content: TendbhaHostContent, + }, + { + id: 'manualInput', + name: t('手动输入'), + tableConfig: { + getTableList: getTendbhaMachineList, + firsrColumn: { + label: t('主库主机'), + field: 'ip', + role: 'master', + }, + columnsChecked: ['ip', 'related_instances', 'cloud_area', 'alive', 'host_name', 'os_name'], + }, + manualConfig: { + checkInstances: getTendbhaMachineList, + checkType: 'ip', + checkKey: 'ip', + activePanelId: 'TendbhaHost', + }, + previewConfig: { + displayKey: 'ip', + }, + content: ManualInputHostContent, + }, + ], TendbClusterHost: [ { id: 'TendbClusterHost', diff --git a/dbm-ui/frontend/src/components/instance-selector/components/common/render-instance/Index.vue b/dbm-ui/frontend/src/components/instance-selector/components/common/render-instance/Index.vue index 3f9e4ea7dc..e9a8cf4c4a 100644 --- a/dbm-ui/frontend/src/components/instance-selector/components/common/render-instance/Index.vue +++ b/dbm-ui/frontend/src/components/instance-selector/components/common/render-instance/Index.vue @@ -8,7 +8,7 @@ {{ item.instance }} diff --git a/dbm-ui/frontend/src/components/instance-selector/components/mysql/table/Index.vue b/dbm-ui/frontend/src/components/instance-selector/components/mysql/table/Index.vue index f18d42364d..98d397265c 100644 --- a/dbm-ui/frontend/src/components/instance-selector/components/mysql/table/Index.vue +++ b/dbm-ui/frontend/src/components/instance-selector/components/mysql/table/Index.vue @@ -106,7 +106,8 @@ cluster_type: data.cluster_type, db_module_id: data.db_module_id, db_module_name: data.db_module_name, - master_domain: data.master_domain, + master_domain: data.master_domain || '', + related_clusters: data.related_clusters || [], role: data.role }); diff --git a/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/Index.vue b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/Index.vue new file mode 100644 index 0000000000..264eac830a --- /dev/null +++ b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/Index.vue @@ -0,0 +1,274 @@ + + + + + + + diff --git a/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/Index.vue b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/Index.vue new file mode 100644 index 0000000000..0a94b9f838 --- /dev/null +++ b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/Index.vue @@ -0,0 +1,301 @@ + + + + + + diff --git a/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/useTableData.ts b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/useTableData.ts new file mode 100644 index 0000000000..2a9a3839a1 --- /dev/null +++ b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/table/useTableData.ts @@ -0,0 +1,102 @@ +/* + * 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 type { ComponentInternalInstance, Ref } from 'vue'; +import { useRequest } from 'vue-request'; + +import { useGlobalBizs } from '@stores'; + +/** + * 处理集群列表数据 + */ +export function useTableData(role?: Ref, clusterId?: Ref) { + const { currentBizId } = useGlobalBizs(); + const currentInstance = getCurrentInstance() as ComponentInternalInstance & { + proxy: { + getTableList: (params: any) => Promise; + }; + }; + + const tableData = shallowRef([]); + const isAnomalies = ref(false); + const pagination = reactive({ + count: 0, + current: 1, + limit: 10, + limitList: [10, 20, 50, 100], + align: 'right', + layout: ['total', 'limit', 'list'], + }); + const searchValue = ref(''); + + const { run: getTableListRun, loading: isLoading } = useRequest(currentInstance.proxy.getTableList, { + manual: true, + onSuccess(data) { + const ret = data; + tableData.value = ret.results; + pagination.count = ret.count; + isAnomalies.value = false; + }, + onError() { + tableData.value = []; + pagination.count = 0; + isAnomalies.value = true; + }, + }); + + watch(searchValue, () => { + setTimeout(() => { + handleChangePage(1); + }); + }); + + const fetchResources = async () => { + const params = { + bk_biz_id: currentBizId, + ip: searchValue.value, + limit: pagination.limit, + offset: (pagination.current - 1) * pagination.limit, + }; + if (role?.value) { + Object.assign(params, { + instance_role: role.value, + }); + } + if (clusterId?.value && clusterId.value !== currentBizId) { + Object.assign(params, { + cluster_ids: clusterId.value, + }); + } + return getTableListRun(params); + }; + + const handleChangePage = (value: number) => { + pagination.current = value; + return fetchResources(); + }; + + const handeChangeLimit = (value: number) => { + pagination.limit = value; + return handleChangePage(1); + }; + + return { + isLoading, + data: tableData, + pagination, + searchValue, + fetchResources, + handleChangePage, + handeChangeLimit, + }; +} diff --git a/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/useTopoData.ts b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/useTopoData.ts new file mode 100644 index 0000000000..f636cd2642 --- /dev/null +++ b/dbm-ui/frontend/src/components/instance-selector/components/tendb-ha-host/useTopoData.ts @@ -0,0 +1,124 @@ +/* + * 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 { type ComponentInternalInstance } from 'vue'; + +import { useGlobalBizs } from '@stores'; + +import { ClusterTypes } from '@common/const'; + +interface TopoTreeData { + id: number; + name: string; + obj: 'biz' | 'cluster'; + count: number; + children: Array; +} + +/** + * 处理集群列表数据 + */ +export function useTopoData>(filterClusterId: ComputedRef) { + const { currentBizId, currentBizInfo } = useGlobalBizs(); + const currentInstance = getCurrentInstance() as ComponentInternalInstance & { + proxy: { + getTopoList: (params: any) => Promise; + countFunc?: (data: T) => number; + firsrColumn?: { + label: string; + field: string; + role: string; + }; + }; + }; + + const isLoading = ref(false); + const selectClusterId = ref(); + const treeRef = ref(); + + const treeData = shallowRef([]); + + /** + * 获取列表 + */ + const fetchResources = async () => { + isLoading.value = true; + const params = { + bk_biz_id: currentBizId, + cluster_filters: [ + { + bk_biz_id: currentBizId, + cluster_type: ClusterTypes.TENDBHA, + }, + ], + } as Record; + if (filterClusterId.value) { + params.cluster_filters[0].id = filterClusterId.value; + } + const role = currentInstance.proxy.firsrColumn?.role; + return currentInstance.proxy + .getTopoList(params) + .then((data) => { + const countFn = currentInstance.proxy?.countFunc; + + const formatData = data.map((item: T) => { + let count = item.instance_count; + if (role === 'slave') { + count = item.slaves?.length || 0; + } else if (role === 'proxy') { + count = item.proxies?.length || 0; + } else if (role === 'master') { + count = item.masters?.length || 0; + } + return { ...item, count: countFn ? countFn(item) : count }; + }); + const children = formatData.map((item: T) => ({ + id: item.id, + name: item.master_domain, + obj: 'cluster', + count: item.count, + children: [], + })); + treeData.value = filterClusterId.value + ? children + : [ + { + name: currentBizInfo?.display_name || '--', + id: currentBizId, + obj: 'biz', + count: formatData.reduce((count: number, item: any) => count + item.count, 0), + children, + }, + ]; + setTimeout(() => { + if (data.length > 0) { + const [firstNode] = treeData.value; + selectClusterId.value = firstNode.id; + const [firstRawNode] = treeRef.value.getData().data; + treeRef.value.setOpen(firstRawNode); + treeRef.value.setSelect(firstRawNode); + } + }); + }) + .finally(() => { + isLoading.value = false; + }); + }; + + return { + treeRef, + isLoading, + treeData, + selectClusterId, + fetchResources, + }; +} diff --git a/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/mysql/proxyReplace.ts b/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/mysql/proxyReplace.ts index 9478de906c..a6887cba46 100644 --- a/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/mysql/proxyReplace.ts +++ b/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/mysql/proxyReplace.ts @@ -13,28 +13,12 @@ import type { MySQLProxySwitchDetails } from '@services/model/ticket/details/mysql'; import TicketModel from '@services/model/ticket/ticket'; -import { random } from '@utils'; - // MySQL 替换Proxy export function generateMysqlProxyReplaceCloneData(ticketData: TicketModel) { const { force, infos } = ticketData.details; - const tableDataList = infos.map((item) => { - const clusterId = item.cluster_ids[0]; - return { - rowKey: random(), - originProxyIp: { - ...item.origin_proxy, - port: item.origin_proxy.port!, - cluster_id: clusterId, - instance_address: `${item.origin_proxy.ip}:${item.origin_proxy.port}`, - }, - targetProxyIp: item.target_proxy, - }; - }); - return Promise.resolve({ force, - tableDataList, + infos, remark: ticketData.remark, }); } diff --git a/dbm-ui/frontend/src/services/model/mysql/tendbha-machine.ts b/dbm-ui/frontend/src/services/model/mysql/tendbha-machine.ts new file mode 100644 index 0000000000..cf2bcfd98d --- /dev/null +++ b/dbm-ui/frontend/src/services/model/mysql/tendbha-machine.ts @@ -0,0 +1,129 @@ +/* + * 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. + */ + +export interface SpecConfig { + id: number; + cpu: { + max: number; + min: number; + }; + mem: { + max: number; + min: number; + }; + qps: unknown; + name: string; + count: number; + device_class: any[]; + storage_spec: { + size: number; + type: string; + mount_point: string; + }[]; +} + +export default class TendbhaMachine { + bk_cloud_id: number; + bk_cloud_name: string; + bk_host_id: number; + cluster_type: string; + create_at: string; + host_info: { + host_id: number; + ip: string; + ipv6: string; + bk_host_outerip: string; + cloud_id: number; + cloud_vendor?: any; + agent_id: string; + host_name: string; + os_name: string; + os_type: string; + alive: number; + cloud_area: { + id: number; + name: string; + }; + bk_mem: number; + bk_disk: number; + bk_cpu: number; + bk_idc_name?: any; + bk_idc_id?: any; + bk_cpu_architecture: string; + bk_cpu_module: string; + meta: { + scope_type: string; + scope_id: string; + bk_biz_id: number; + }; + biz: { + id: number; + name: string; + }; + }; + instance_role: string; + ip: string; + machine_type: string; + related_clusters: { + id: number; + creator: string; + updater: string; + name: string; + alias: string; + bk_biz_id: number; + cluster_type: string; + db_module_id: number; + immute_domain: string; + major_version: string; + phase: string; + status: string; + bk_cloud_id: number; + region: string; + disaster_tolerance_level: string; + time_zone: string; + cluster_type_name: string; + tag: any[]; + }[]; + related_instances: { + name: string; + ip: string; + port: number; + instance: string; + status: string; + phase: string; + bk_instance_id: number; + bk_host_id: number; + bk_cloud_id: number; + spec_config: SpecConfig; + bk_biz_id: number; + admin_port: number; + }[]; + spec_config: SpecConfig; + spec_id: number; + + constructor(payload = {} as TendbhaMachine) { + this.bk_cloud_id = payload.bk_cloud_id; + this.bk_cloud_name = payload.bk_cloud_name; + this.bk_host_id = payload.bk_host_id; + this.cluster_type = payload.cluster_type; + this.create_at = payload.create_at; + this.host_info = payload.host_info; + this.instance_role = payload.instance_role; + this.ip = payload.ip; + this.machine_type = payload.machine_type; + this.related_clusters = payload.related_clusters; + this.related_instances = payload.related_instances; + this.spec_config = payload.spec_config; + this.spec_id = payload.spec_id; + } +} diff --git a/dbm-ui/frontend/src/services/source/instances.ts b/dbm-ui/frontend/src/services/source/instances.ts index 336f659c7f..3328a12d7e 100644 --- a/dbm-ui/frontend/src/services/source/instances.ts +++ b/dbm-ui/frontend/src/services/source/instances.ts @@ -14,7 +14,7 @@ import RedisClusterNodeByIpModel from '@services/model/redis/redis-cluster-node-by-ip'; import http from '../http'; -import type { InstanceInfos } from '../types/clusters'; +import type { InstanceInfos } from '../types/instanceInfos'; /** * 判断 Mysql 实例是否存在 diff --git a/dbm-ui/frontend/src/services/source/tendbha.ts b/dbm-ui/frontend/src/services/source/tendbha.ts index 8949628608..d0b46bcdb4 100644 --- a/dbm-ui/frontend/src/services/source/tendbha.ts +++ b/dbm-ui/frontend/src/services/source/tendbha.ts @@ -14,6 +14,7 @@ import TendbhaModel from '@services/model/mysql/tendbha'; import TendbhaDetailModel from '@services/model/mysql/tendbha-detail'; import TendbhaInstanceModel from '@services/model/mysql/tendbha-instance'; +import TendbhaMachineModel from '@services/model/mysql/tendbha-machine'; import type { ListBase, ResourceTopo } from '@services/types'; import http from '../http'; @@ -155,3 +156,24 @@ export function exportTendbhaClusterToExcel(params: { cluster_ids?: number[] }) export function exportTendbhaInstanceToExcel(params: { bk_host_ids?: number[] }) { return http.post(`${getRootPath()}/export_instance/`, params, { responseType: 'blob' }); } + +/** + * 查询主机列表 + */ +export function getTendbhaMachineList(params: { + limit?: number; + offset?: number; + bk_host_id?: number; + ip?: string; + machine_type?: string; + bk_os_name?: string; + bk_cloud_id?: number; + bk_agent_id?: string; + instance_role?: string; + creator?: string; +}) { + return http.get>(`${getRootPath()}/list_machines/`, params).then((data) => ({ + ...data, + results: data.results.map((item) => new TendbhaMachineModel(item)), + })); +} diff --git a/dbm-ui/frontend/src/views/db-manage/mysql/proxy-replace/pages/page1/Index.vue b/dbm-ui/frontend/src/views/db-manage/mysql/proxy-replace/pages/page1/Index.vue index 668497ce8c..67888b7277 100644 --- a/dbm-ui/frontend/src/views/db-manage/mysql/proxy-replace/pages/page1/Index.vue +++ b/dbm-ui/frontend/src/views/db-manage/mysql/proxy-replace/pages/page1/Index.vue @@ -12,49 +12,45 @@ -->