From 5efeab1c631b391348e83e7b48cc8acf9b912d8d Mon Sep 17 00:00:00 2001 From: gaoyunshan Date: Thu, 9 Jan 2025 15:52:55 +0800 Subject: [PATCH] V3.0.1 --- core.py | 13 +- plugins/general/0.1/chown_dir.py | 1 + plugins/ocp-server/4.2.1/connect.py | 20 +-- plugins/ocp-server/4.2.1/start.py | 4 +- .../MetaDBConfig/DataBaseNodeConfig.tsx | 11 +- web/src/pages/Obdeploy/NodeConfig.tsx | 26 +++- web/src/utils/index.tsx | 119 ++++++++++++++++++ workflows/ocp-server/4.2.1/add_component.py | 3 +- workflows/ocp-server/4.2.1/reinstall.py | 4 +- workflows/ocp-server/4.2.1/restart.py | 5 +- workflows/ocp-server/4.2.1/scale_out.py | 2 +- workflows/ocp-server/4.2.1/start.py | 3 +- workflows/ocp-server/4.2.1/upgrade_start.py | 3 +- 13 files changed, 180 insertions(+), 34 deletions(-) diff --git a/core.py b/core.py index ae94f658..d5ebbec7 100644 --- a/core.py +++ b/core.py @@ -1310,6 +1310,7 @@ def export_to_ocp(self, name): return False self._call_stdio('verbose', 'Get Deploy by name') deploy = self.deploy_manager.get_deploy_config(name) + self.set_deploy(deploy) if not deploy: self._call_stdio('error', 'No such deploy: %s.' % name) return False @@ -1328,12 +1329,6 @@ def export_to_ocp(self, name): self.set_repositories(repositories) ssh_clients = self.get_clients(deploy_config, repositories) - self._call_stdio('verbose', 'get plugins by mocking an ocp repository.') - # search and get all related plugins using a mock ocp repository - mock_ocp_repository = Repository(const.COMP_OCP_SERVER_CE, "/") - mock_ocp_repository.version = "4.2.1" - repositories.extend([mock_ocp_repository]) - # search and install oceanbase-ce-utils, just log warning when failed since it can be installed after takeover repositories_utils_map = self.get_repositories_utils(repositories) if not repositories_utils_map: @@ -1342,6 +1337,12 @@ def export_to_ocp(self, name): if not self.install_utils_to_servers(repositories, repositories_utils_map): self._call_stdio('warn', 'Failed to install utils to servers') + self._call_stdio('verbose', 'get plugins by mocking an ocp repository.') + # search and get all related plugins using a mock ocp repository + mock_ocp_repository = Repository(const.COMP_OCP_SERVER_CE, "/") + mock_ocp_repository.version = "4.2.1" + repositories.extend([mock_ocp_repository]) + self.set_deploy(None) workflow = self.get_workflows('take_over', repositories=[mock_ocp_repository] + self.repositories, no_found_act='ignore') if not self.run_workflow(workflow, deploy_config=deploy_config, repositories=[mock_ocp_repository] + self.repositories, no_found_act='ignore', **{mock_ocp_repository.name: {'cluster_config': cluster_config, 'clients': ssh_clients}}): return False diff --git a/plugins/general/0.1/chown_dir.py b/plugins/general/0.1/chown_dir.py index c3820803..75b3ae0e 100644 --- a/plugins/general/0.1/chown_dir.py +++ b/plugins/general/0.1/chown_dir.py @@ -72,6 +72,7 @@ def dir_read_check(client, path): if not new_client.execute_command(chown_cmd): stdio.stop_loading('stop_loading', 'fail') return False + chown_dir_flags = False dir_read_check(new_client, server_config['home_path']) return plugin_context.return_true() diff --git a/plugins/ocp-server/4.2.1/connect.py b/plugins/ocp-server/4.2.1/connect.py index d659d721..74cc95d1 100644 --- a/plugins/ocp-server/4.2.1/connect.py +++ b/plugins/ocp-server/4.2.1/connect.py @@ -76,27 +76,27 @@ def status(self, stdio=None): return False def info(self, stdio=None): - resp = self._request('GET', '/api/v2/info', stdio=stdio) + resp = self._request('GET', '/api/v2/info', stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content def upload_packages(self, files, stdio=None): - resp = self._request('POST', '/api/v2/software-packages', files=files, stdio=stdio) + resp = self._request('POST', '/api/v2/software-packages', files=files, stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content def take_over_precheck(self, data, stdio=None): - resp = self._request('POST', '/api/v2/ob/clusters/takeOverPreCheck', data=data, stdio=stdio) + resp = self._request('POST', '/api/v2/ob/clusters/takeOverPreCheck', data=data, stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content def get_host_types(self, stdio=None): - resp = self._request('GET', '/api/v2/compute/hostTypes', stdio=stdio) + resp = self._request('GET', '/api/v2/compute/hostTypes', stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content def create_host_type(self, data, stdio=None): - resp = self._request('POST', '/api/v2/compute/hostTypes', data=data, stdio=stdio) + resp = self._request('POST', '/api/v2/compute/hostTypes', data=data, stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content else: @@ -106,7 +106,7 @@ def create_host_type(self, data, stdio=None): raise Exception("failed to create host type: %s" % msg) def list_credentials(self, stdio=None): - resp = self._request('GET', '/api/v2/profiles/me/credentials', stdio=stdio) + resp = self._request('GET', '/api/v2/profiles/me/credentials', stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content else: @@ -116,7 +116,7 @@ def list_credentials(self, stdio=None): raise Exception("failed to query credentials: %s" % msg) def create_credential(self, data, stdio=None): - resp = self._request('POST', '/api/v2/profiles/me/credentials', data=data, stdio=stdio) + resp = self._request('POST', '/api/v2/profiles/me/credentials', data=data, stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content else: @@ -126,7 +126,7 @@ def create_credential(self, data, stdio=None): raise Exception("failed to create credential: %s" % msg) def take_over(self, data, stdio=None): - resp = self._request('POST', '/api/v2/ob/clusters/takeOver', data=data, stdio=stdio) + resp = self._request('POST', '/api/v2/ob/clusters/takeOver', data=data, stdio=stdio, auth=self.auth) if resp.code == 200: return resp.content else: @@ -135,14 +135,14 @@ def take_over(self, data, stdio=None): msg = resp.content['error']['message'] raise Exception("failed to do take over: %s" % msg) - def _request(self, method, api, data=None, files=None, retry=5, stdio=None): + def _request(self, method, api, data=None, files=None, retry=5, stdio=None, auth=None): url = self.url_prefix + api headers = {'Content-Type': 'application/json'} if not files else {} try: if data is not None: data = json.dumps(data) stdio.verbose('send http request method: {}, url: {}, data: {}, files: {}'.format(method, url, data, files)) - resp = requests.request(method, url, data=data, files=files, verify=False, headers=headers, auth=self.auth) + resp = requests.request(method, url, data=data, files=files, verify=False, headers=headers, auth=auth) return_code = resp.status_code content = resp.content except Exception as e: diff --git a/plugins/ocp-server/4.2.1/start.py b/plugins/ocp-server/4.2.1/start.py index acf85e36..fc4f45bd 100644 --- a/plugins/ocp-server/4.2.1/start.py +++ b/plugins/ocp-server/4.2.1/start.py @@ -29,7 +29,7 @@ from tool import get_option -def start(plugin_context, start_env=None, *args, **kwargs): +def start(plugin_context, multi_process_flag=False, start_env=None, *args, **kwargs): EXCLUDE_KEYS = plugin_context.get_variable('EXCLUDE_KEYS') CONFIG_MAPPER = plugin_context.get_variable('CONFIG_MAPPER') @@ -146,7 +146,7 @@ def start(plugin_context, start_env=None, *args, **kwargs): success = False continue client.write_file(server_pid[server], os.path.join(home_path, 'run/ocp-server.pid')) - if len(cluster_config.servers) > 1: + if not multi_process_flag and len(cluster_config.servers) > 1: break if len(cluster_config.servers) > 1 and node_num == 1: time.sleep(60) diff --git a/web/src/component/MetaDBConfig/DataBaseNodeConfig.tsx b/web/src/component/MetaDBConfig/DataBaseNodeConfig.tsx index 2f1fca0b..63bd8e07 100644 --- a/web/src/component/MetaDBConfig/DataBaseNodeConfig.tsx +++ b/web/src/component/MetaDBConfig/DataBaseNodeConfig.tsx @@ -10,9 +10,9 @@ import { useEffect, useState } from 'react'; import { useModel } from 'umi'; import ServerTags from '@/pages/Obdeploy/ServerTags'; -import { serversValidator } from '@/utils'; import { getAllServers } from '@/utils/helper'; import styles from './index.less'; +import { IPserversValidator } from '@/utils'; interface DataBaseNodeConfigProps { tableFormRef: React.MutableRefObject< @@ -151,7 +151,14 @@ export default function DataBaseNodeConfig({ }, { validator: (_: any, value: string[]) => { - return serversValidator(_, value, 'OBServer'); + return IPserversValidator( + _, + value, + allOBServer, + 'OBServer', + allZoneOBServer, + finalValidate, + ); }, }, ], diff --git a/web/src/pages/Obdeploy/NodeConfig.tsx b/web/src/pages/Obdeploy/NodeConfig.tsx index e427b3ad..651f5a62 100644 --- a/web/src/pages/Obdeploy/NodeConfig.tsx +++ b/web/src/pages/Obdeploy/NodeConfig.tsx @@ -1,5 +1,11 @@ import { getObdInfo } from '@/services/ob-deploy-web/Info'; -import { getErrorInfo, handleQuit, serverReg, serversValidator } from '@/utils'; +import { + getErrorInfo, + handleQuit, + IPserversValidator, + serverReg, + serversValidator, +} from '@/utils'; import { getAllServers } from '@/utils/helper'; import { intl } from '@/utils/intl'; import useRequest from '@/utils/useRequest'; @@ -59,7 +65,12 @@ export default function NodeConfig() { errorsList, } = useModel('global'); const { components = {}, auth, home_path } = configData || {}; - const { oceanbase = {}, ocpexpress = {}, obproxy = {}, obconfigserver = {} } = components; + const { + oceanbase = {}, + ocpexpress = {}, + obproxy = {}, + obconfigserver = {}, + } = components; const [form] = ProForm.useForm(); const [editableForm] = ProForm.useForm(); const finalValidate = useRef(false); @@ -167,7 +178,6 @@ export default function NodeConfig() { servers: item?.servers?.map((server) => ({ ip: server })), })), }; - setConfigData({ ...configData, components: newComponents, @@ -458,7 +468,14 @@ export default function NodeConfig() { }, { validator: (_: any, value: string[]) => - serversValidator(_, value, 'OBServer'), + IPserversValidator( + _, + value, + allOBServer, + 'OBServer', + allZoneOBServer, + finalValidate, + ), }, ], }, @@ -643,7 +660,6 @@ export default function NodeConfig() { editableItem?.id, 'servers', ]); - if (editorServers.length) { if (!rootService || !editorServers.includes(rootService)) { newRootService = editorServers[0]; diff --git a/web/src/utils/index.tsx b/web/src/utils/index.tsx index 0a31e875..c51d6a7f 100644 --- a/web/src/utils/index.tsx +++ b/web/src/utils/index.tsx @@ -225,6 +225,125 @@ export const updateClusterNameReg = /^[a-zA-Z][a-zA-Z0-9_-]{0,30}[a-zA-Z0-9]$/; //用户格式:以英文字母开头,可包含英文、数字、下划线和连字符,且不超过32位 export const nameReg = /^[a-zA-Z][a-zA-Z0-9_-]{0,31}$/; +const checkIsRepeatByAllServers = (allZoneServers: any, id: string) => { + let currentServers: string[] = [], + otherServers: string[] = []; + Object.keys(allZoneServers).forEach((key) => { + if (id === key) { + currentServers = [...allZoneServers[key]]; + } else { + otherServers = [...otherServers, ...allZoneServers[key]]; + } + }); + for (let server of currentServers) { + if (otherServers.includes(server)) { + return true; + } + } + return false; +}; + +const checkIp = (value: string[], type: 'OBServer' | 'OBProxy'): ResultType => { + let response: ResultType = { success: false, msg: '' }; + if (value && value.length) { + value.some((item) => { + response.success = serverReg.test(item.trim()); + return !serverReg.test(item.trim()); + }); + } + if (!response.success) { + response.msg = + type === 'OBServer' + ? intl.formatMessage({ + id: 'OBD.src.utils.EnterTheCorrectIpAddress', + defaultMessage: '请输入正确的 IP 地址', + }) + : intl.formatMessage({ + id: 'OBD.src.utils.SelectTheCorrectObproxyNode', + defaultMessage: '请选择正确的 OBProxy 节点', + }); + } + return response; +}; + +const checkIsRepeatByPreServers = ( + preAllServers: string[], + inputServer: string, +) => { + if (preAllServers.includes(inputServer)) { + return true; + } + return false; +}; + +const checkRepeat = ( + finalValidate, + allZoneServers, + id, + inputServer, + preAllServers, + type, +) => { + let response: ResultType = { msg: '', success: true }; + if (type === 'OBProxy') return response; + if (finalValidate.current) { + response.success = !checkIsRepeatByAllServers(allZoneServers, id); + } else { + response.success = !checkIsRepeatByPreServers(preAllServers, inputServer); + } + if (!response.success) { + response.msg = intl.formatMessage({ + id: 'OBD.src.utils.DoNotEnterDuplicateNodes', + defaultMessage: '禁止输入重复节点', + }); + } + return response; +}; + +type ResultType = { + success: boolean; + msg: string; +}; +const resultHandlePipeline = (...results: ResultType[]): ResultType => { + for (let result of results) { + if (!result.success) { + return result; + } + } + return { + success: true, + msg: '', + }; +}; +export const IPserversValidator = ( + _: any, + value: string[], + preAllServers: string[], + type: 'OBServer' | 'OBProxy', + allZoneServers?: any, + finalValidate?: any, +) => { + let result: ResultType = { + success: false, + msg: '', + }, + inputServer = value[0]; + let id = _.field?.split('.')[0]; + result = resultHandlePipeline( + checkIp(value, type), + checkRepeat( + finalValidate, + allZoneServers, + id, + inputServer, + preAllServers, + type, + ), + ); + if (!result.success) return Promise.reject(new Error(result.msg)); + return Promise.resolve(); +}; + export const ocpServersValidator = (_: any, value: string[]) => { let validtor = true; if (value && value.length) { diff --git a/workflows/ocp-server/4.2.1/add_component.py b/workflows/ocp-server/4.2.1/add_component.py index 141ef211..0116645c 100644 --- a/workflows/ocp-server/4.2.1/add_component.py +++ b/workflows/ocp-server/4.2.1/add_component.py @@ -28,6 +28,7 @@ def add_component(plugin_context, workflow, *args, **kwargs): workflow.add(const.STAGE_SECOND, 'parameter_pre', 'ocp_const', 'cursor_check', 'start', 'health_check', 'stop_pre') workflow.add_with_component(const.STAGE_SECOND, 'general', 'stop') - workflow.add(const.STAGE_SECOND, 'start', 'health_check', 'bootstrap') + workflow.add_with_kwargs(const.STAGE_SECOND, {'multi_process_flag': True}, 'start') + workflow.add(const.STAGE_SECOND, 'health_check', 'bootstrap') plugin_context.return_true() diff --git a/workflows/ocp-server/4.2.1/reinstall.py b/workflows/ocp-server/4.2.1/reinstall.py index d11a6e51..ea13004d 100644 --- a/workflows/ocp-server/4.2.1/reinstall.py +++ b/workflows/ocp-server/4.2.1/reinstall.py @@ -25,5 +25,7 @@ def reinstall(plugin_context, workflow, *args, **kwargs): workflow.add(const.STAGE_FIRST, 'parameter_pre') - workflow.add_with_kwargs(const.STAGE_FIRST, {'is_reinstall': True}, 'cursor_check', 'start', 'health_check', 'stop', 'start', 'health_check') + workflow.add_with_kwargs(const.STAGE_FIRST, {'is_reinstall': True}, 'cursor_check', 'start') + workflow.add_with_component(const.STAGE_FIRST, 'general', 'stop') + workflow.add_with_kwargs(const.STAGE_FIRST, {'is_reinstall': True, 'multi_process_flag': True}, 'start', 'health_check') plugin_context.return_true() diff --git a/workflows/ocp-server/4.2.1/restart.py b/workflows/ocp-server/4.2.1/restart.py index 0b66df4b..cc49cc20 100644 --- a/workflows/ocp-server/4.2.1/restart.py +++ b/workflows/ocp-server/4.2.1/restart.py @@ -38,7 +38,7 @@ def restart(plugin_context, workflow, *args, **kwargs): if not plugin_context.cluster_config.depends: workflow.add_with_kwargs(const.STAGE_FIRST, {'need_connect': False}, 'cursor_check') workflow.add_with_kwargs(const.STAGE_FIRST, {'cursor': cursor if cursor else None, 'need_bootstrap': need_bootstrap, - 'clients': new_clients if new_clients else clients, 'new_cluster_config': new_cluster_config, + 'clients': new_clients if new_clients else clients, 'new_cluster_config': new_cluster_config, 'multi_process_flag': True, 'cluster_config': new_cluster_config if new_cluster_config else cluster_config}, 'parameter_pre', 'ocp_const', 'start', 'health_check') finally_plugins = plugin_context.get_variable('finally_plugins') @@ -55,6 +55,3 @@ def restart(plugin_context, workflow, *args, **kwargs): return plugin_context.return_true() - - - diff --git a/workflows/ocp-server/4.2.1/scale_out.py b/workflows/ocp-server/4.2.1/scale_out.py index 72df9f18..70ba2667 100644 --- a/workflows/ocp-server/4.2.1/scale_out.py +++ b/workflows/ocp-server/4.2.1/scale_out.py @@ -34,6 +34,6 @@ def scale_out(plugin_context, workflow, *args, **kwargs): workflow.add(const.STAGE_THIRD, 'parameter_pre', 'ocp_const') workflow.add_with_kwargs(const.STAGE_THIRD, {'target_servers': added_servers}, 'cursor_check', 'start', 'health_check') workflow.add_with_component_version_kwargs(const.STAGE_THIRD, 'general', '0.1', {'target_servers': added_servers}, 'stop') - workflow.add_with_kwargs(const.STAGE_THIRD, {'target_servers': added_servers}, 'start', 'health_check', 'bootstrap') + workflow.add_with_kwargs(const.STAGE_THIRD, {'target_servers': added_servers, 'multi_process_flag': True}, 'start', 'health_check', 'bootstrap') plugin_context.return_true() diff --git a/workflows/ocp-server/4.2.1/start.py b/workflows/ocp-server/4.2.1/start.py index 568fb167..3a74127f 100644 --- a/workflows/ocp-server/4.2.1/start.py +++ b/workflows/ocp-server/4.2.1/start.py @@ -36,5 +36,6 @@ def start(plugin_context, workflow, *args, **kwargs): workflow.add(const.STAGE_FIRST, 'start', 'health_check') workflow.add(const.STAGE_FIRST, 'stop_pre') workflow.add_with_component(const.STAGE_FIRST, 'general', 'stop') - workflow.add(const.STAGE_FIRST, 'start', 'health_check', 'bootstrap', 'connect', 'upload_packages') + workflow.add_with_kwargs(const.STAGE_FIRST, {'multi_process_flag': True}, 'start') + workflow.add(const.STAGE_FIRST, 'health_check', 'bootstrap', 'connect', 'upload_packages') plugin_context.return_true() diff --git a/workflows/ocp-server/4.2.1/upgrade_start.py b/workflows/ocp-server/4.2.1/upgrade_start.py index 68773993..b52fd3c3 100644 --- a/workflows/ocp-server/4.2.1/upgrade_start.py +++ b/workflows/ocp-server/4.2.1/upgrade_start.py @@ -27,5 +27,6 @@ def upgrade_start(plugin_context, workflow, *args, **kwargs): workflow.add(const.STAGE_FIRST, 'parameter_pre', 'ocp_const') if not plugin_context.cluster_config.depends: workflow.add_with_kwargs(const.STAGE_FIRST, {'need_connect': False}, 'cursor_check') - workflow.add(const.STAGE_FIRST, 'start', 'health_check', 'bootstrap', 'connect', 'display') + workflow.add_with_kwargs(const.STAGE_FIRST, {'multi_process_flag': True}, 'start') + workflow.add(const.STAGE_FIRST, 'health_check', 'bootstrap', 'connect', 'display') plugin_context.return_true()