From 485ac87a86f7b7ba80222af06794ec1fa9e70c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 29 Jul 2024 17:23:57 +0800 Subject: [PATCH 01/35] update io: add stderr --- stdio.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/stdio.py b/stdio.py index 2a0f86cf..a82ff35c 100644 --- a/stdio.py +++ b/stdio.py @@ -240,7 +240,7 @@ def align(self, val): class IOHalo(Halo): - def __init__(self, text='', color='cyan', text_color=None, spinner='line', animation=None, placement='right', interval=-1, enabled=True, stream=sys.stdout): + def __init__(self, text='', color='cyan', text_color=None, spinner='line', animation=None, placement='right', interval=-1, enabled=True, stream=sys.stdout,error_stream=sys.stderr): super(IOHalo, self).__init__(text=text, color=color, text_color=text_color, spinner=spinner, animation=animation, placement=placement, interval=interval, enabled=enabled, stream=stream) def start(self, text=None): @@ -358,7 +358,7 @@ class IO(object): WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout): + def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout,error_stream=sys.stderr): self.level = level self.msg_lv = msg_lv self.default_confirm = False @@ -379,6 +379,8 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self._input_is_tty = False self.set_input_stream(input_stream) self.set_output_stream(output_stream) + self._cur_err_obj = None + self.set_err_stream(error_stream) def isatty(self): if self._root_io: @@ -399,6 +401,12 @@ def set_output_stream(self, output_stream): self._out_obj = output_stream self._output_is_tty = output_stream.isatty() return True + def set_err_stream(self, error_stream): + if self._root_io: + return False + self._cur_err_obj = error_stream + self._output_is_tty = error_stream.isatty() + return True def init_trace_logger(self, log_path, log_name=None, trace_id=None, recreate=False): if self._root_io: @@ -500,6 +508,10 @@ def get_input_stream(self): if self._root_io: return self._root_io.get_input_stream() return self.input_stream + def get_cur_err_obj(self): + if self._root_io: + return self._root_io.get_cur_err_obj() + return self._cur_err_obj def get_cur_out_obj(self): if self._root_io: @@ -680,7 +692,10 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - kwargs['file'] = self.get_cur_out_obj() + if msg_lv == MsgLevel.ERROR: + kwargs['file'] = self.get_cur_err_obj() + else: + kwargs['file'] = self.get_cur_out_obj() kwargs['file'] and print(self._format(print_msg, *args), **kwargs) del kwargs['file'] self.log(msg_lv, msg, *args, **kwargs) From 7595ea7dff71e7ba0e3fefb343d6df1e88128d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 29 Jul 2024 19:17:32 +0800 Subject: [PATCH 02/35] update io: add stderr --- stdio.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/stdio.py b/stdio.py index a82ff35c..c56038a7 100644 --- a/stdio.py +++ b/stdio.py @@ -240,7 +240,7 @@ def align(self, val): class IOHalo(Halo): - def __init__(self, text='', color='cyan', text_color=None, spinner='line', animation=None, placement='right', interval=-1, enabled=True, stream=sys.stdout,error_stream=sys.stderr): + def __init__(self, text='', color='cyan', text_color=None, spinner='line', animation=None, placement='right', interval=-1, enabled=True, stream=sys.stdout): super(IOHalo, self).__init__(text=text, color=color, text_color=text_color, spinner=spinner, animation=animation, placement=placement, interval=interval, enabled=enabled, stream=stream) def start(self, text=None): @@ -358,7 +358,7 @@ class IO(object): WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout,error_stream=sys.stderr): + def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stderr): self.level = level self.msg_lv = msg_lv self.default_confirm = False @@ -373,13 +373,14 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self.sync_obj = None self.input_stream = None self._out_obj = None + self._err_obj = None self._cur_out_obj = None + self._cur_err_obj = None self._before_critical = None self._output_is_tty = False self._input_is_tty = False self.set_input_stream(input_stream) self.set_output_stream(output_stream) - self._cur_err_obj = None self.set_err_stream(error_stream) def isatty(self): @@ -401,10 +402,13 @@ def set_output_stream(self, output_stream): self._out_obj = output_stream self._output_is_tty = output_stream.isatty() return True + def set_err_stream(self, error_stream): if self._root_io: return False - self._cur_err_obj = error_stream + if self._cur_err_obj == self._err_obj: + self._cur_err_obj = error_stream + self._err_obj = error_stream self._output_is_tty = error_stream.isatty() return True @@ -425,7 +429,7 @@ def __getstate__(self): state = {} for key in self.__dict__: state[key] = self.__dict__[key] - for key in ['_trace_logger', 'input_stream', 'sync_obj', '_out_obj', '_cur_out_obj', '_before_critical']: + for key in ['_trace_logger', 'input_stream', 'sync_obj', '_out_obj', '_cur_out_obj', '_before_critical', '_cur_err_obj']: state[key] = None return state @@ -508,6 +512,7 @@ def get_input_stream(self): if self._root_io: return self._root_io.get_input_stream() return self.input_stream + def get_cur_err_obj(self): if self._root_io: return self._root_io.get_cur_err_obj() @@ -524,6 +529,7 @@ def _start_buffer_io(self): if self._cur_out_obj != self._out_obj: return False self._cur_out_obj = BufferIO() + self._cur_err_obj = BufferIO() return True def _stop_buffer_io(self): @@ -533,6 +539,7 @@ def _stop_buffer_io(self): return False text = self._cur_out_obj.read() self._cur_out_obj = self._out_obj + self._cur_err_obj = self._err_obj if text: self.print(text) return True From 6dcb146a79f1d019c1416ff17a28ec6e39bced47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 30 Jul 2024 17:33:07 +0800 Subject: [PATCH 03/35] add --inner_config add print_type --- config.py | 7 ++++++- core.py | 9 +++++++-- diag_cmd.py | 37 ++++++++++++++++++++++++++++++++++++- stdio.py | 9 ++++++++- 4 files changed, 57 insertions(+), 5 deletions(-) diff --git a/config.py b/config.py index 9deb6f3b..d7702b5c 100644 --- a/config.py +++ b/config.py @@ -65,6 +65,7 @@ 'file_number_limit': 20, 'file_size_limit': '2G', 'dis_rsa_algorithms': 0, + 'print_type': 0, }, 'logger': { 'log_dir': '~/.obdiag/log', @@ -257,7 +258,11 @@ def get_node_config(self, type, node_ip, config_item): class InnerConfigManager(Manager): - def __init__(self, stdio=None): + def __init__(self, stdio=None, inner_config_change_map=None): + if inner_config_change_map is None: + inner_config_change_map = {} inner_config_abs_path = os.path.abspath(INNER_CONFIG_FILE) super().__init__(inner_config_abs_path, stdio=stdio) self.config = self.load_config_with_defaults(DEFAULT_INNER_CONFIG) + if inner_config_change_map != {}: + self.config.update(inner_config_change_map) diff --git a/core.py b/core.py index 73f8a956..c19c1d39 100644 --- a/core.py +++ b/core.py @@ -62,7 +62,7 @@ class ObdiagHome(object): - def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config.yml')): + def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config.yml'), inner_config_change_map=None): self._optimize_manager = None self.stdio = None self._stdio_func = None @@ -71,7 +71,12 @@ def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config. self.namespaces = {} self.set_stdio(stdio) self.context = None - self.inner_config_manager = InnerConfigManager(stdio) + self.inner_config_manager = InnerConfigManager(stdio=stdio, inner_config_change_map=inner_config_change_map) + if self.inner_config_manager.config.get("obdiag") is not None and self.inner_config_manager.config.get("obdiag").get("basic") is not None and self.inner_config_manager.config.get("obdiag").get("basic").get("print_type") is not None: + stdio.set_print_type(self.inner_config_manager.config.get("obdiag").get("basic").get("print_type")) + pass + + self.set_stdio(stdio) self.config_manager = ConfigManager(config_path, stdio) if ( self.inner_config_manager.config.get("obdiag") is not None diff --git a/diag_cmd.py b/diag_cmd.py index 394e931d..f67aa07e 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -111,13 +111,48 @@ def __init__(self, name, summary): self.is_init = False self.hidden = False self.has_trace = True + self.inner_config_change_map = {} self.parser = AllowUndefinedOptionParser(add_help_option=True) self.parser.add_option('-h', '--help', action='callback', callback=self._show_help, help='Show help and exit.') self.parser.add_option('-v', '--verbose', action='callback', callback=self._set_verbose, help='Activate verbose output.') + self.parser.add_option('--inner_config', action='callback', type="str", callback=self._inner_config_change, help='change inner config. ') def _set_verbose(self, *args, **kwargs): ROOT_IO.set_verbose_level(0xFFFFFFF) + def _inner_config_change(self, option, opt_str, value, parser): + """ + Inner config change + """ + try: + key, val = value.split('=') + if key is None or key == "": + return + print("{0}: {1}".format(key, val)) + m = self._inner_config_change_set(key, val) + self.inner_config_change_map.update(m) + print("map update to: {0}".format(self.inner_config_change_map)) + except Exception as e: + raise Exception("Key or val ({1}:{2}) is illegal: {0}".format(e, key, val)) + + def _inner_config_change_set(self, key, val): + def recursion(change_map, key, val): + if key is None or key == "": + raise Exception("key is None") + if val is None or val == "": + raise Exception("val is None") + if key.startswith(".") or key.endswith("."): + raise Exception("Key starts or ends '.'") + if "." in key: + map_key = key.split(".")[0] + change_map[map_key] = recursion({}, key[len(map_key) + 1 :], val) + return change_map + else: + change_map[key] = val + return change_map + + return recursion({}, key, val) + def init(self, cmd, args): if self.is_init is False: self.prev_cmd = cmd @@ -216,7 +251,7 @@ def do_command(self): else: ROOT_IO.error('The option you provided with -c: {0} is a non-existent configuration file path.'.format(custom_config)) return - obdiag = ObdiagHome(stdio=ROOT_IO, config_path=config_path) + obdiag = ObdiagHome(stdio=ROOT_IO, config_path=config_path, inner_config_change_map=self.inner_config_change_map) obdiag.set_options(self.opts) obdiag.set_cmds(self.cmds) ret = self._do_command(obdiag) diff --git a/stdio.py b/stdio.py index c56038a7..fa0d401e 100644 --- a/stdio.py +++ b/stdio.py @@ -382,6 +382,13 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self.set_input_stream(input_stream) self.set_output_stream(output_stream) self.set_err_stream(error_stream) + self.print_type = 0 # 0: use stdout, 1: use stdout and stderr, 2: just print result (json). when obdiag_version ≥ 3.0, print_type = 1 + + def set_print_type(self, print_type=0): + try: + self.print_type = int(print_type) + except Exception as e: + pass def isatty(self): if self._root_io: @@ -699,7 +706,7 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - if msg_lv == MsgLevel.ERROR: + if msg_lv == MsgLevel.ERROR and self.print_type > 0: kwargs['file'] = self.get_cur_err_obj() else: kwargs['file'] = self.get_cur_out_obj() From 7d59f258e25764679e3a7808dfe1043d90d2f87c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 30 Jul 2024 20:18:16 +0800 Subject: [PATCH 04/35] support remote_client_sudo --- common/command.py | 31 ------------------------------ common/ssh_client/remote_client.py | 13 ++++++++++++- config.py | 3 +++ diag_cmd.py | 4 +--- stdio.py | 5 +++-- 5 files changed, 19 insertions(+), 37 deletions(-) diff --git a/common/command.py b/common/command.py index 2af96419..81efec54 100644 --- a/common/command.py +++ b/common/command.py @@ -48,37 +48,6 @@ def run_get_stderr(self, cmd): self.stdio.error("run cmd = [{0}] on localhost".format(cmd)) -# -# class SshClient(object): -# def __init__(self, stdio=None): -# self.stdio = stdio -# -# def run(self, ssh_helper, cmd): -# try: -# self.stdio.verbose("[remote host {0}] excute cmd = [{1}]".format(ssh_helper.get_name(), cmd)) -# stdout = ssh_helper.ssh_exec_cmd(cmd) -# self.stdio.verbose("[remote host {0}] excute cmd = [{1}] complete, stdout=[{2}]".format(ssh_helper.get_name(), cmd, stdout)) -# return stdout -# except Exception as e: -# self.stdio.error("[remote host {0}] excute cmd = [{1}] except: [{2}]".format(ssh_helper.get_name(), cmd, e)) -# -# def run_get_stderr(self, ssh_helper, cmd): -# try: -# self.stdio.verbose("[remote host {0}] run cmd = [{1}] start ...".format(ssh_helper.get_name(), cmd)) -# std = ssh_helper.ssh_exec_cmd_get_stderr(cmd) -# return std -# except Exception as e: -# self.stdio.error("[remote host {0}] run ssh cmd = [{1}] except: {2}".format(ssh_helper.get_name(), cmd, e)) -# -# def run_ignore_err(self, ssh_helper, cmd): -# try: -# self.stdio.verbose("[remote host {0}] run cmd = [{1}] start ...".format(ssh_helper.get_name(), cmd)) -# std = ssh_helper.ssh_exec_cmd_ignore_err(cmd) -# return std -# except SSHException as e: -# self.stdio.error("[remote host {0}] run ssh cmd = [{1}] except: {2}".format(ssh_helper.get_name(), cmd, e)) - - def download_file(ssh_client, remote_path, local_path, stdio=None): """ download file diff --git a/common/ssh_client/remote_client.py b/common/ssh_client/remote_client.py index b128be0e..5516324a 100644 --- a/common/ssh_client/remote_client.py +++ b/common/ssh_client/remote_client.py @@ -50,8 +50,12 @@ def __init__(self, context, node): self.key_file = os.path.expanduser(self.key_file) self._ssh_fd = None self._sftp_client = None + # remote_client_sudo + self.remote_client_sudo = bool(self.context.inner_config.get("obdiag").get("ssh_client").get("remote_client_sudo")) + # remote_client_disable_rsa_algorithms DISABLED_ALGORITHMS = dict(pubkeys=["rsa-sha2-512", "rsa-sha2-256"]) - if ENV_DISABLE_RSA_ALGORITHMS == 1: + remote_client_disable_rsa_algorithms = bool(self.context.inner_config.get("obdiag").get("basic").get("dis_rsa_algorithms")) + if remote_client_disable_rsa_algorithms: self._disabled_rsa_algorithms = DISABLED_ALGORITHMS self.ssh_type = "remote" if len(self.key_file) > 0: @@ -75,6 +79,13 @@ def __init__(self, context, node): def exec_cmd(self, cmd): try: + if self.remote_client_sudo: + # check sudo without password + self.stdio.verbose("use remote_client_sudo") + stdin, stdout, stderr = self._ssh_fd.exec_command("sudo -n true") + if stderr: + raise Exception(stderr.read().decode('utf-8')) + cmd = "sudo {0}".format(cmd) stdin, stdout, stderr = self._ssh_fd.exec_command(cmd) err_text = stderr.read() if len(err_text): diff --git a/config.py b/config.py index d7702b5c..eee86812 100644 --- a/config.py +++ b/config.py @@ -75,6 +75,9 @@ 'mode': 'obdiag', 'stdout_handler_log_level': 'INFO', }, + 'ssh_client': { + 'remote_client_sudo': False, + }, }, 'check': { 'ignore_version': False, diff --git a/diag_cmd.py b/diag_cmd.py index f67aa07e..2a5c9e7b 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -128,12 +128,10 @@ def _inner_config_change(self, option, opt_str, value, parser): key, val = value.split('=') if key is None or key == "": return - print("{0}: {1}".format(key, val)) m = self._inner_config_change_set(key, val) self.inner_config_change_map.update(m) - print("map update to: {0}".format(self.inner_config_change_map)) except Exception as e: - raise Exception("Key or val ({1}:{2}) is illegal: {0}".format(e, key, val)) + raise Exception("Key or val ({1}) is illegal: {0}".format(e, value)) def _inner_config_change_set(self, key, val): def recursion(change_map, key, val): diff --git a/stdio.py b/stdio.py index fa0d401e..96b70795 100644 --- a/stdio.py +++ b/stdio.py @@ -382,7 +382,8 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self.set_input_stream(input_stream) self.set_output_stream(output_stream) self.set_err_stream(error_stream) - self.print_type = 0 # 0: use stdout, 1: use stdout and stderr, 2: just print result (json). when obdiag_version ≥ 3.0, print_type = 1 + # TODO print on doc + self.print_type = 0 # 0: use stdout, 1: use stdout and stderr, 2: just print result (json). when obdiag_version ≥ 3.0, print_type default 1 def set_print_type(self, print_type=0): try: @@ -706,7 +707,7 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - if msg_lv == MsgLevel.ERROR and self.print_type > 0: + if msg_lv == MsgLevel.ERROR and self.print_type == 1: kwargs['file'] = self.get_cur_err_obj() else: kwargs['file'] = self.get_cur_out_obj() From 454f803d49d2ebd90bef8faebeec09f5cea3ba3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 30 Jul 2024 20:43:19 +0800 Subject: [PATCH 05/35] build test package --- .github/workflows/build_package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_package.yml b/.github/workflows/build_package.yml index 6287fa6e..342949cd 100644 --- a/.github/workflows/build_package.yml +++ b/.github/workflows/build_package.yml @@ -7,6 +7,7 @@ on: push: branches: - master + - 2.4.0-io-update env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true From 90697d977791046d22fae83555e177ef55556315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 31 Jul 2024 16:04:52 +0800 Subject: [PATCH 06/35] fix --inner_config --- config.py | 13 ++++++++++++- diag_cmd.py | 14 +++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index eee86812..0ff7d58e 100644 --- a/config.py +++ b/config.py @@ -268,4 +268,15 @@ def __init__(self, stdio=None, inner_config_change_map=None): super().__init__(inner_config_abs_path, stdio=stdio) self.config = self.load_config_with_defaults(DEFAULT_INNER_CONFIG) if inner_config_change_map != {}: - self.config.update(inner_config_change_map) + self.config = self._change_inner_config(self.config, inner_config_change_map) + + def _change_inner_config(self, conf_map, change_conf_map): + for key, value in change_conf_map.items(): + if key in conf_map: + if isinstance(value, dict): + self._change_inner_config(conf_map[key], value) + else: + conf_map[key] = value + else: + conf_map[key] = value + return conf_map diff --git a/diag_cmd.py b/diag_cmd.py index 2a5c9e7b..c54012dc 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -129,7 +129,19 @@ def _inner_config_change(self, option, opt_str, value, parser): if key is None or key == "": return m = self._inner_config_change_set(key, val) - self.inner_config_change_map.update(m) + + def _change_inner_config(conf_map, change_conf_map): + for change_conf_map_key, change_conf_map_value in change_conf_map.items(): + if change_conf_map_key in conf_map: + if isinstance(change_conf_map_value, dict): + _change_inner_config(conf_map[change_conf_map_key], change_conf_map_value) + else: + conf_map[change_conf_map_key] = change_conf_map_value + else: + conf_map[change_conf_map_key] = change_conf_map_value + return conf_map + + self.inner_config_change_map = _change_inner_config(self.inner_config_change_map, m) except Exception as e: raise Exception("Key or val ({1}) is illegal: {0}".format(e, value)) From e2c2250513495fbd4feb4869d11543c516ae4949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 31 Jul 2024 17:20:46 +0800 Subject: [PATCH 07/35] fix io stream --- conf/inner_config.yml | 3 +++ config.py | 2 +- core.py | 3 +-- diag_cmd.py | 3 ++- stdio.py | 39 ++++++++++++++++++++++++++++----------- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/conf/inner_config.yml b/conf/inner_config.yml index c0480eda..db4aa329 100644 --- a/conf/inner_config.yml +++ b/conf/inner_config.yml @@ -12,6 +12,9 @@ obdiag: log_level: INFO mode: obdiag stdout_handler_log_level: INFO + error_stream: sys.stdout + ssh_client: + remote_client_sudo: 0 check: ignore_version: false work_path: "~/.obdiag/check" diff --git a/config.py b/config.py index 0ff7d58e..cc2fc19f 100644 --- a/config.py +++ b/config.py @@ -65,7 +65,6 @@ 'file_number_limit': 20, 'file_size_limit': '2G', 'dis_rsa_algorithms': 0, - 'print_type': 0, }, 'logger': { 'log_dir': '~/.obdiag/log', @@ -74,6 +73,7 @@ 'log_level': 'INFO', 'mode': 'obdiag', 'stdout_handler_log_level': 'INFO', + 'error_stream': 'sys.stdout', }, 'ssh_client': { 'remote_client_sudo': False, diff --git a/core.py b/core.py index c19c1d39..3a7d996c 100644 --- a/core.py +++ b/core.py @@ -73,8 +73,7 @@ def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config. self.context = None self.inner_config_manager = InnerConfigManager(stdio=stdio, inner_config_change_map=inner_config_change_map) if self.inner_config_manager.config.get("obdiag") is not None and self.inner_config_manager.config.get("obdiag").get("basic") is not None and self.inner_config_manager.config.get("obdiag").get("basic").get("print_type") is not None: - stdio.set_print_type(self.inner_config_manager.config.get("obdiag").get("basic").get("print_type")) - pass + stdio.set_err_stream(self.inner_config_manager.config.get("obdiag").get("logger").get("error_stream")) self.set_stdio(stdio) self.config_manager = ConfigManager(config_path, stdio) diff --git a/diag_cmd.py b/diag_cmd.py index c54012dc..ccca161d 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -29,7 +29,8 @@ from common.version import get_obdiag_version from telemetry.telemetry import telemetry -ROOT_IO = IO(1) +# TODO when obdiag_version ≥ 3.0, the default value of err_stream will be changed to sys.stderr +ROOT_IO = IO(1, error_stream=sys.stdout) OBDIAG_HOME_PATH = os.path.join(os.getenv('HOME'), 'oceanbase-diagnostic-tool') diff --git a/stdio.py b/stdio.py index 96b70795..bdb10105 100644 --- a/stdio.py +++ b/stdio.py @@ -13,6 +13,7 @@ from __future__ import absolute_import, division, print_function +import json import os import signal import sys @@ -358,7 +359,7 @@ class IO(object): WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stderr): + def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout): self.level = level self.msg_lv = msg_lv self.default_confirm = False @@ -382,14 +383,6 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self.set_input_stream(input_stream) self.set_output_stream(output_stream) self.set_err_stream(error_stream) - # TODO print on doc - self.print_type = 0 # 0: use stdout, 1: use stdout and stderr, 2: just print result (json). when obdiag_version ≥ 3.0, print_type default 1 - - def set_print_type(self, print_type=0): - try: - self.print_type = int(print_type) - except Exception as e: - pass def isatty(self): if self._root_io: @@ -412,6 +405,15 @@ def set_output_stream(self, output_stream): return True def set_err_stream(self, error_stream): + if isinstance(error_stream, str): + error_stream = error_stream.strip().lower() + if error_stream == "sys.stderr": + error_stream = sys.stderr + elif error_stream == "sys.stdout": + error_stream = sys.stdout + else: + # TODO 3.X NEED CHANGE TO sys.stderr + error_stream = sys.stdout if self._root_io: return False if self._cur_err_obj == self._err_obj: @@ -437,7 +439,7 @@ def __getstate__(self): state = {} for key in self.__dict__: state[key] = self.__dict__[key] - for key in ['_trace_logger', 'input_stream', 'sync_obj', '_out_obj', '_cur_out_obj', '_before_critical', '_cur_err_obj']: + for key in ['_trace_logger', 'input_stream', 'sync_obj', '_out_obj', '_err_obj', '_cur_out_obj', '_cur_err_obj', '_before_critical']: state[key] = None return state @@ -545,11 +547,16 @@ def _stop_buffer_io(self): return False if self._cur_out_obj == self._out_obj: return False + if self._cur_err_obj == self._err_obj: + return False text = self._cur_out_obj.read() + text_err = self._cur_err_obj.read() self._cur_out_obj = self._out_obj self._cur_err_obj = self._err_obj if text: self.print(text) + if text_err: + self.error(text_err) return True @staticmethod @@ -707,7 +714,7 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - if msg_lv == MsgLevel.ERROR and self.print_type == 1: + if msg_lv == MsgLevel.ERROR: kwargs['file'] = self.get_cur_err_obj() else: kwargs['file'] = self.get_cur_out_obj() @@ -763,6 +770,16 @@ def verbose(self, msg, *args, **kwargs): return self._print(MsgLevel.VERBOSE, '%s %s' % (self._verbose_prefix, msg), *args, **kwargs) + def print_result_json(self, result): + + if not result: + return + if isinstance(result, dict): + result = json.dumps(result, indent=4) + self.print(result) + + pass + if sys.version_info.major == 2: def exception(self, msg='', *args, **kwargs): From 15cca2c2979455e33dffabe67e9b34b5c22b39f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Thu, 1 Aug 2024 15:40:32 +0800 Subject: [PATCH 08/35] test --- common/ssh_client/remote_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/ssh_client/remote_client.py b/common/ssh_client/remote_client.py index 5516324a..311aa785 100644 --- a/common/ssh_client/remote_client.py +++ b/common/ssh_client/remote_client.py @@ -84,7 +84,8 @@ def exec_cmd(self, cmd): self.stdio.verbose("use remote_client_sudo") stdin, stdout, stderr = self._ssh_fd.exec_command("sudo -n true") if stderr: - raise Exception(stderr.read().decode('utf-8')) + if len(stderr.read().decode('utf-8').strip())> 0: + raise Exception(stderr.read().decode('utf-8')) cmd = "sudo {0}".format(cmd) stdin, stdout, stderr = self._ssh_fd.exec_command(cmd) err_text = stderr.read() From 9789b87937de60baa23a7e8a10b73af6fc2acc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Thu, 1 Aug 2024 15:41:10 +0800 Subject: [PATCH 09/35] test --- common/ssh_client/remote_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ssh_client/remote_client.py b/common/ssh_client/remote_client.py index 311aa785..6e0e0854 100644 --- a/common/ssh_client/remote_client.py +++ b/common/ssh_client/remote_client.py @@ -84,7 +84,7 @@ def exec_cmd(self, cmd): self.stdio.verbose("use remote_client_sudo") stdin, stdout, stderr = self._ssh_fd.exec_command("sudo -n true") if stderr: - if len(stderr.read().decode('utf-8').strip())> 0: + if len(stderr.read().decode('utf-8').strip()) > 0: raise Exception(stderr.read().decode('utf-8')) cmd = "sudo {0}".format(cmd) stdin, stdout, stderr = self._ssh_fd.exec_command(cmd) From 3e4cf734474c27ea6918bafb6a72d2cdcb6a50e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Thu, 1 Aug 2024 16:56:20 +0800 Subject: [PATCH 10/35] test --- handler/gather/gather_log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handler/gather/gather_log.py b/handler/gather/gather_log.py index 6001296a..80f6cb81 100644 --- a/handler/gather/gather_log.py +++ b/handler/gather/gather_log.py @@ -281,9 +281,9 @@ def __get_log_name(self, ssh_client, node): home_path = node.get("home_path") log_path = os.path.join(home_path, "log") if self.scope == "observer" or self.scope == "rootservice" or self.scope == "election": - get_oblog = "ls -1 -F %s/*%s.log* | awk -F '/' '{print $NF}'" % (log_path, self.scope) + get_oblog = "ls -1 -F %s |grep %s | awk -F '/' '{print $NF}'" % (log_path, self.scope) else: - get_oblog = "ls -1 -F %s/observer.log* %s/rootservice.log* %s/election.log* | awk -F '/' '{print $NF}'" % (log_path, log_path, log_path) + get_oblog = "ls -1 -F %s |grep -E 'observer|rootservice|election'| awk -F '/' '{print $NF}'" % log_path log_name_list = [] log_files = ssh_client.exec_cmd(get_oblog) if log_files: From 3e5ba9446594f14f664764d6ccd941c797b889fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 2 Aug 2024 11:44:17 +0800 Subject: [PATCH 11/35] test --- common/ssh_client/remote_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ssh_client/remote_client.py b/common/ssh_client/remote_client.py index 6e0e0854..c17c874b 100644 --- a/common/ssh_client/remote_client.py +++ b/common/ssh_client/remote_client.py @@ -87,6 +87,7 @@ def exec_cmd(self, cmd): if len(stderr.read().decode('utf-8').strip()) > 0: raise Exception(stderr.read().decode('utf-8')) cmd = "sudo {0}".format(cmd) + self.stdio.verbose('Execute Shell command on server {0}:{1}'.format(self.host_ip, cmd)) stdin, stdout, stderr = self._ssh_fd.exec_command(cmd) err_text = stderr.read() if len(err_text): From 0f0ea77bc99f5b224a626b1a78a8669a655b43c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 2 Aug 2024 15:04:25 +0800 Subject: [PATCH 12/35] test --- common/command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/command.py b/common/command.py index 81efec54..915d0f60 100644 --- a/common/command.py +++ b/common/command.py @@ -189,7 +189,7 @@ def zip_dir(ssh_client, father_dir, zip_dir, stdio=None): Compress files through zip :return: """ - cmd = "cd {father_dir} && zip {zip_dir}.zip -rm {zip_dir}".format(father_dir=father_dir, zip_dir=zip_dir) + cmd = "zip {father_dir}/{zip_dir}.zip -rm {father_dir}/{zip_dir}".format(father_dir=father_dir, zip_dir=zip_dir) ssh_client.exec_cmd(cmd) @@ -198,7 +198,7 @@ def zip_encrypt_dir(ssh_client, zip_password, father_dir, zip_dir, stdio=None): Compress files by encryption :return: """ - cmd = "cd {father_dir} && zip --password {zip_password} {zip_dir}.zip -rm {zip_dir}".format(zip_password=zip_password, father_dir=father_dir, zip_dir=zip_dir) + cmd = "zip --password {zip_password} {father_dir}/{zip_dir}.zip -rm {father_dir}/{zip_dir}".format(zip_password=zip_password, father_dir=father_dir, zip_dir=zip_dir) ssh_client.exec_cmd(cmd) From 3329cbd56320535f9ecfe0a0b6ee8e2b898c01b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 5 Aug 2024 10:59:11 +0800 Subject: [PATCH 13/35] =?UTF-8?q?=E5=8F=96=E6=B6=88=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=88=86=E6=94=AF=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_package.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_package.yml b/.github/workflows/build_package.yml index 342949cd..6287fa6e 100644 --- a/.github/workflows/build_package.yml +++ b/.github/workflows/build_package.yml @@ -7,7 +7,6 @@ on: push: branches: - master - - 2.4.0-io-update env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true From 4785d96255f6845e385805f4c5eeb575e308cd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 7 Aug 2024 19:49:33 +0800 Subject: [PATCH 14/35] test --- core.py | 63 ++++++++------ diag_cmd.py | 35 ++++---- handler/checker/check_handler.py | 3 +- handler/checker/check_list.py | 82 +++++++++++-------- .../tasks/observer/cluster/task_opt_stat.yaml | 16 ++++ .../tasks/observer/system/parameter.yaml | 2 +- result_type.py | 37 +++++++++ 7 files changed, 159 insertions(+), 79 deletions(-) create mode 100644 handler/checker/tasks/observer/cluster/task_opt_stat.yaml create mode 100644 result_type.py diff --git a/core.py b/core.py index 3a7d996c..969cfe46 100644 --- a/core.py +++ b/core.py @@ -76,6 +76,12 @@ def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config. stdio.set_err_stream(self.inner_config_manager.config.get("obdiag").get("logger").get("error_stream")) self.set_stdio(stdio) + if config_path: + if os.path.exists(os.path.abspath(config_path)): + config_path = config_path + else: + stdio.error('The option you provided with -c: {0} is not exist.'.format(config_path)) + return self.config_manager = ConfigManager(config_path, stdio) if ( self.inner_config_manager.config.get("obdiag") is not None @@ -313,31 +319,38 @@ def analyze_fuction(self, function_type, opt): return False def check(self, opts): - config = self.config_manager - if not config: - self._call_stdio('error', 'No such custum config') - return False - else: - self.stdio.print("check start ...") - self.set_context('check', 'check', config) - obproxy_check_handler = None - observer_check_handler = None - if self.context.obproxy_config.get("servers") is not None and len(self.context.obproxy_config.get("servers")) > 0: - obproxy_check_handler = CheckHandler(self.context, check_target_type="obproxy") - obproxy_check_handler.handle() - obproxy_check_handler.execute() - if self.context.cluster_config.get("servers") is not None and len(self.context.cluster_config.get("servers")) > 0: - observer_check_handler = CheckHandler(self.context, check_target_type="observer") - observer_check_handler.handle() - observer_check_handler.execute() - if obproxy_check_handler is not None: - obproxy_report_path = os.path.expanduser(obproxy_check_handler.report.get_report_path()) - if os.path.exists(obproxy_report_path): - self.stdio.print("Check obproxy finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(obproxy_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") - if observer_check_handler is not None: - observer_report_path = os.path.expanduser(observer_check_handler.report.get_report_path()) - if os.path.exists(observer_report_path): - self.stdio.print("Check observer finished. For more details, please run cmd'" + Fore.YELLOW + " cat {0} ".format(observer_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") + try: + result_map = {"data": {}} + config = self.config_manager + if not config: + self._call_stdio('error', 'No such custum config') + return False + else: + self.stdio.print("check start ...") + self.set_context('check', 'check', config) + obproxy_check_handler = None + observer_check_handler = None + if self.context.obproxy_config.get("servers") is not None and len(self.context.obproxy_config.get("servers")) > 0: + obproxy_check_handler = CheckHandler(self.context, check_target_type="obproxy") + obproxy_check_handler.handle() + report = obproxy_check_handler.execute() + result_map["data"]["obproxy"] = report.report_tobeMap() + if self.context.cluster_config.get("servers") is not None and len(self.context.cluster_config.get("servers")) > 0: + observer_check_handler = CheckHandler(self.context, check_target_type="observer") + observer_check_handler.handle() + report = observer_check_handler.execute() + result_map["data"]["observer"] = report.report_tobeMap() + if obproxy_check_handler is not None: + obproxy_report_path = os.path.expanduser(obproxy_check_handler.report.get_report_path()) + if os.path.exists(obproxy_report_path): + self.stdio.print("Check obproxy finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(obproxy_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") + if observer_check_handler is not None: + observer_report_path = os.path.expanduser(observer_check_handler.report.get_report_path()) + if os.path.exists(observer_report_path): + self.stdio.print("Check observer finished. For more details, please run cmd'" + Fore.YELLOW + " cat {0} ".format(observer_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") + except Exception as e: + self.stdio.error("check Exception: {0}".format(e)) + self.stdio.verbose(traceback.format_exc()) def check_list(self, opts): config = self.config_manager diff --git a/diag_cmd.py b/diag_cmd.py index ccca161d..09ca1f5f 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -25,6 +25,7 @@ from uuid import uuid1 as uuid, UUID from optparse import OptionParser, BadOptionError, Option, IndentedHelpFormatter from core import ObdiagHome +from result_type import ObdiagResult from stdio import IO from common.version import get_obdiag_version from telemetry.telemetry import telemetry @@ -194,6 +195,10 @@ def _mk_usage(self): class ObdiagOriginCommand(BaseCommand): OBDIAG_PATH = OBDIAG_HOME_PATH + def __init__(self, name, summary): + super().__init__(name, summary) + self.trace_id = uuid() + @property def enable_log(self): return True @@ -242,7 +247,6 @@ def parse_command(self): def do_command(self): self.parse_command() - trace_id = uuid() ret = False try: log_directory = os.path.join(os.path.expanduser("~"), ".obdiag", "log") @@ -250,23 +254,26 @@ def do_command(self): os.makedirs(log_directory, exist_ok=True) log_path = os.path.join(log_directory, 'obdiag.log') if self.enable_log: - ROOT_IO.init_trace_logger(log_path, 'obdiag', trace_id) + ROOT_IO.init_trace_logger(log_path, 'obdiag', self.trace_id) ROOT_IO.track_limit += 1 - ROOT_IO.verbose('cmd: %s' % self.cmds) + ROOT_IO.verbose('cmd: %s' % self.prev_cmd) ROOT_IO.verbose('opts: %s' % self.opts) config_path = os.path.expanduser('~/.obdiag/config.yml') custom_config = Util.get_option(self.opts, 'c') - if custom_config: - if os.path.exists(os.path.abspath(custom_config)): - config_path = custom_config - else: - ROOT_IO.error('The option you provided with -c: {0} is a non-existent configuration file path.'.format(custom_config)) - return - obdiag = ObdiagHome(stdio=ROOT_IO, config_path=config_path, inner_config_change_map=self.inner_config_change_map) + obdiag = ObdiagHome(stdio=ROOT_IO, config_path=custom_config, inner_config_change_map=self.inner_config_change_map) obdiag.set_options(self.opts) obdiag.set_cmds(self.cmds) ret = self._do_command(obdiag) + if isinstance(ret, ObdiagResult) is False: + ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) + return + ret.set_trace_id(self.trace_id) telemetry.put_data() + if self.has_trace: + ROOT_IO.print('Trace ID: %s' % self.trace_id) + ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin,self.trace_id)) + return ret or ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) + except NotImplementedError: ROOT_IO.exception('command \'%s\' is not implemented' % self.prev_cmd) except SystemExit: @@ -276,10 +283,7 @@ def do_command(self): except: e = sys.exc_info()[1] ROOT_IO.exception('Running Error: %s' % e) - if self.has_trace: - ROOT_IO.print('Trace ID: %s' % trace_id) - ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, trace_id)) - return ret or True + def _do_command(self, obdiag): raise NotImplementedError @@ -856,8 +860,7 @@ def init(self, cmd, args): def _do_command(self, obdiag): if 'list' in self.args: - obdiag.check_list(self.opts) - return + return obdiag.check_list(self.opts) return obdiag.check(self.opts) diff --git a/handler/checker/check_handler.py b/handler/checker/check_handler.py index e74b9ccf..340d77c6 100644 --- a/handler/checker/check_handler.py +++ b/handler/checker/check_handler.py @@ -101,7 +101,6 @@ def __init__(self, context, check_target_type="observer"): # add ssher ssher = None try: - # ssher = SshHelper(True, node.get("ip"), node.get("ssh_username"), node.get("ssh_password"), node.get("ssh_port"), node.get("ssh_key_file"), node) ssher = SshClient(context, node) except Exception as e: self.stdio.warn("StepBase get SshHelper fail on{0} ,Exception: {1}".format(node.get("ip"), e)) @@ -113,7 +112,6 @@ def __init__(self, context, check_target_type="observer"): # add OBConnectorPool try: obConnectorPool = checkOBConnectorPool(context, 3, self.cluster) - except Exception as e: self.stdio.warn("obConnector init error. Error info is {0}".format(e)) finally: @@ -243,6 +241,7 @@ def execute(self): t_report = self.execute_one(task) self.report.add_task_report(t_report) self.report.export_report() + return self.report except CheckrReportException as e: self.stdio.error("Report error :{0}".format(e)) self.stdio.verbose(traceback.format_exc()) diff --git a/handler/checker/check_list.py b/handler/checker/check_list.py index 53ab952c..03e405cf 100644 --- a/handler/checker/check_list.py +++ b/handler/checker/check_list.py @@ -20,6 +20,7 @@ import yaml from common.tool import Util +from result_type import ObdiagResult class CheckListHandler: @@ -29,41 +30,52 @@ def __init__(self, context): self.work_path = os.path.expanduser(self.context.inner_config["check"]["work_path"] or "~/.obdiag/check") def handle(self): - self.stdio.verbose("list check cases") - entries = os.listdir(self.work_path) - files = [f for f in entries if os.path.isfile(os.path.join(self.work_path, f))] - for file in files: - if "check_package" in file: - cases_map = {"all": {"name": "all", "command": "obdiag check", "info_en": "default check all task without filter", "info_cn": "默认执行除filter组里的所有巡检项"}} - # Obtain which files match and corresponding header files - # Using string segmentation methods - parts = file.split('_') - if len(parts) < 1: - self.stdio.warn("invalid check package name :{0} , Please don't add file, which 'check_package' in the name".format(file)) - continue - target = parts[0] - file = "{0}/{1}".format(self.work_path, file) - package_file_data = None - # read yaml file - with open(file, 'r') as f: - package_file_data = yaml.safe_load(f) - if not package_file_data or len(package_file_data) == 0: - self.stdio.warn("No data check package data :{0} ".format(file)) + try: + self.stdio.verbose("list check cases") + entries = os.listdir(self.work_path) + files = [f for f in entries if os.path.isfile(os.path.join(self.work_path, f))] + result_map = {"data": {}} + for file in files: + if "check_package" in file: + cases_map = {"all": {"name": "all", "command": "obdiag check", "info_en": "default check all task without filter", "info_cn": "默认执行除filter组里的所有巡检项"}} + # Obtain which files match and corresponding header files + # Using string segmentation methods + parts = file.split('_') + if len(parts) < 1: + self.stdio.warn("invalid check package name :{0} , Please don't add file, which 'check_package' in the name".format(file)) continue - for package_data in package_file_data: - if package_data == "filter": + target = parts[0] + file = "{0}/{1}".format(self.work_path, file) + package_file_data = None + # read yaml file + with open(file, 'r') as f: + package_file_data = yaml.safe_load(f) + if not package_file_data or len(package_file_data) == 0: + self.stdio.warn("No data check package data :{0} ".format(file)) continue - package_target = target - if target == "observer": - package_target = "cases" - else: - package_target = "{0}_cases".format(target) + for package_data in package_file_data: + if package_data == "filter": + continue + package_target = target + if target == "observer": + package_target = "cases" + else: + package_target = "{0}_cases".format(target) - cases_map[package_data] = { - "name": package_data, - "command": "obdiag check --{0}={1}".format(package_target, package_data), - "info_en": package_file_data[package_data].get("info_en") or "", - "info_cn": package_file_data[package_data].get("info_cn") or "", - } - Util.print_title("check cases about {0}".format(target)) - Util.print_scene(cases_map) + cases_map[package_data] = { + "name": package_data, + "command": "obdiag check --{0}={1}".format(package_target, package_data), + "info_en": package_file_data[package_data].get("info_en") or "", + "info_cn": package_file_data[package_data].get("info_cn") or "", + } + result_map["data"]["commands"] = { + "name": package_data, + "command": "obdiag check --{0}={1}".format(package_target, package_data), + "info_en": package_file_data[package_data].get("info_en") or "", + "info_cn": package_file_data[package_data].get("info_cn") or "", + } + Util.print_title("check cases about {0}".format(target)) + Util.print_scene(cases_map) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, result_map) + except Exception as e: + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data=str(e)) diff --git a/handler/checker/tasks/observer/cluster/task_opt_stat.yaml b/handler/checker/tasks/observer/cluster/task_opt_stat.yaml new file mode 100644 index 00000000..7b1fbcf5 --- /dev/null +++ b/handler/checker/tasks/observer/cluster/task_opt_stat.yaml @@ -0,0 +1,16 @@ +info: 'Check whether data_dir and log_dir_disk are on the same disk.' +task: + - version: "[4.2.0.0,*]" + steps: + - type: sql + ssh: 'SELECT GROUP_CONCAT(DISTINCT TENANT_ID) +FROM oceanbase.__all_tenant t +WHERE NOT EXISTS(SELECT 1 + FROM oceanbase.__all_virtual_task_opt_stat_gather_history h + WHERE TYPE = 1 + AND start_time > date_sub(now(), interval 1 day) + AND h.tenant_id = t.tenant_id);' + result: + set_value: failed_scheduler_tenant_id + verify: '[ -n "${failed_scheduler_tenant_id}" ]' + err_msg: "failed_scheduler_tenant_id is exists. Please check the tenant_ids: #{failed_scheduler_tenant_id}" \ No newline at end of file diff --git a/handler/checker/tasks/observer/system/parameter.yaml b/handler/checker/tasks/observer/system/parameter.yaml index 38fc7fd7..3be8519f 100644 --- a/handler/checker/tasks/observer/system/parameter.yaml +++ b/handler/checker/tasks/observer/system/parameter.yaml @@ -176,7 +176,7 @@ task: set_value: parameter report_type: warning verify: "[ 6573688 -le ${parameter} ]" - err_msg: 'fs.file-max: #{parameter}. recommended: #{parameter} is ≥ 6573688.' + err_msg: 'fs.file-max: #{parameter}. recommended: is ≥ 6573688.' - type: get_system_parameter parameter: fs.pipe-user-pages-soft result: diff --git a/result_type.py b/result_type.py new file mode 100644 index 00000000..2d144b2a --- /dev/null +++ b/result_type.py @@ -0,0 +1,37 @@ +class ObdiagResult: + # ObdiagResult is the result of obdiag. + # It contains the code and result of obdiag. + + # SERVER_ERROR_CODE(5xx) is the code of server error. + SERVER_ERROR_CODE = 500 + # INPUT_ERROR_CODE(4xx) is the code of input error. + INPUT_ERROR_CODE = 400 + # SUCCESS_CODE(200) is the code of success. + SUCCESS_CODE = 200 + + def __init__(self, code, data=None, error_data=None): + self.trace_id = None + self.data = data + self.error_data = error_data + if code is None: + raise TypeError("ObdiagResult code is None. Please contact the Oceanbase community. ") + if isinstance(code, int): + self.code = str(code) + else: + raise TypeError("ObdiagResult code is not int. Please contact the Oceanbase community. ") + if isinstance(data, dict): + self.result = data + else: + raise TypeError("ObdiagResult result is not str. Please contact the Oceanbase community. ") + if isinstance(error_data, str): + self.error_data = error_data + else: + raise TypeError("ObdiagResult error_data is not str. Please contact the Oceanbase community. ") + + def set_trace_id(self, trace_id): + if trace_id is None: + raise TypeError("ObdiagResult trace_id is None. Please contact the Oceanbase community. ") + if isinstance(trace_id, str): + self.trace_id = trace_id + else: + raise TypeError("ObdiagResult trace_id is not str. Please contact the Oceanbase community. ") From 6848ba532ec07055fd74895421a0c7f5aada679b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 7 Aug 2024 19:50:14 +0800 Subject: [PATCH 15/35] test --- diag_cmd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/diag_cmd.py b/diag_cmd.py index 09ca1f5f..e7265d1f 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -271,7 +271,7 @@ def do_command(self): telemetry.put_data() if self.has_trace: ROOT_IO.print('Trace ID: %s' % self.trace_id) - ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin,self.trace_id)) + ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, self.trace_id)) return ret or ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) except NotImplementedError: @@ -284,7 +284,6 @@ def do_command(self): e = sys.exc_info()[1] ROOT_IO.exception('Running Error: %s' % e) - def _do_command(self, obdiag): raise NotImplementedError From 7c1e5460e9257c95710be2234e05d0b1b89f895a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 7 Aug 2024 20:24:28 +0800 Subject: [PATCH 16/35] test --- common/command.py | 12 ++++++------ common/config_helper.py | 2 +- common/ssh_client/base.py | 1 - common/ssh_client/remote_client.py | 1 - common/tool.py | 16 ++++++++-------- core.py | 7 ++++--- handler/checker/check_list.py | 4 ++-- handler/gather/scenes/list.py | 12 ++++++------ handler/rca/rca_list.py | 2 +- stdio.py | 6 ++++-- 10 files changed, 32 insertions(+), 31 deletions(-) diff --git a/common/command.py b/common/command.py index 915d0f60..4677e2e1 100644 --- a/common/command.py +++ b/common/command.py @@ -405,12 +405,12 @@ def is_empty_file(ssh_client, file_path, stdio=None): return False -def get_obdiag_display(log_dir, trace_id, stdio=None): - cmd = 'grep -h "\[{}\]" {}* | sed "s/\[{}\] //g" '.format(trace_id, log_dir, trace_id) - stdout = LocalClient(stdio).run(cmd) - print_stdout = str(stdout).replace('\\n', '\n').replace('\\t', '\t') - if len(print_stdout) > 0: - print(print_stdout) +# def get_obdiag_display(log_dir, trace_id, stdio=None): +# cmd = 'grep -h "\[{}\]" {}* | sed "s/\[{}\] //g" '.format(trace_id, log_dir, trace_id) +# stdout = LocalClient(stdio).run(cmd) +# print_stdout = str(stdout).replace('\\n', '\n').replace('\\t', '\t') +# if len(print_stdout) > 0: +# print(print_stdout) def uzip_dir_local(uzip_dir, stdio=None): diff --git a/common/config_helper.py b/common/config_helper.py index 4fcc55ed..a27e5ccd 100644 --- a/common/config_helper.py +++ b/common/config_helper.py @@ -98,7 +98,7 @@ def build_configuration(self): self.save_old_configuration(old_config) # rewrite config ob_cluster_name = self.get_cluster_name() - print("\033[33mPlease enter the following configuration !!!\033[0m") + self.stdio.print("\033[33mPlease enter the following configuration !!!\033[0m") global_ssh_username = self.input_with_default("oceanbase host ssh username", "") global_ssh_password = self.input_password_with_default("oceanbase host ssh password", "") global_ssh_port = self.input_with_default("oceanbase host ssh_port", "22") diff --git a/common/ssh_client/base.py b/common/ssh_client/base.py index 870f73b5..16021e7c 100644 --- a/common/ssh_client/base.py +++ b/common/ssh_client/base.py @@ -62,7 +62,6 @@ def progress_bar(self, transferred, to_be_transferred, suffix=''): sys.stdout.write('Downloading [%s] %s%s%s %s %s\r' % (bar, '\033[32;1m%s\033[0m' % print_percents, '% [', self.translate_byte(transferred), ']', suffix)) if transferred == to_be_transferred: sys.stdout.write('Downloading [%s] %s%s%s %s %s\r' % (bar, '\033[32;1m%s\033[0m' % print_percents, '% [', self.translate_byte(transferred), ']', suffix)) - print() def translate_byte(self, B): if B < 0: diff --git a/common/ssh_client/remote_client.py b/common/ssh_client/remote_client.py index c17c874b..d61c0821 100644 --- a/common/ssh_client/remote_client.py +++ b/common/ssh_client/remote_client.py @@ -113,7 +113,6 @@ def progress_bar(self, transferred, to_be_transferred, suffix=''): sys.stdout.write('Downloading [%s] %s%s%s %s %s\r' % (bar, '\033[32;1m%s\033[0m' % print_percents, '% [', self.translate_byte(transferred), ']', suffix)) if transferred == to_be_transferred: sys.stdout.write('Downloading [%s] %s%s%s %s %s\r' % (bar, '\033[32;1m%s\033[0m' % print_percents, '% [', self.translate_byte(transferred), ']', suffix)) - print() def upload(self, remote_path, local_path): transport = self._ssh_fd.get_transport() diff --git a/common/tool.py b/common/tool.py index 0e9921a2..0ab14007 100644 --- a/common/tool.py +++ b/common/tool.py @@ -1358,26 +1358,26 @@ def convert_to_number(s, stdio=None): return s @staticmethod - def print_scene(scene_dict, stdio=None): + def print_scene(scene_dict, stdio): columns_to_print = ['command', 'info_en', 'info_cn'] keys = columns_to_print table_data = [[value[key] for key in keys] for value in scene_dict.values()] column_widths = [max(len(str(item)) * (StringUtils.is_chinese(item) or 1) for item in column) for column in zip(*table_data)] table_data.insert(0, keys) - Util.print_line(length=sum(column_widths) + 5) + Util.print_line(length=sum(column_widths) + 5, stdio=stdio) for i in range(len(table_data)): - print(Fore.GREEN + " ".join(f"{item:<{width}}" for item, width in zip(table_data[i], column_widths)) + Style.RESET_ALL) + stdio.print(Fore.GREEN + " ".join(f"{item:<{width}}" for item, width in zip(table_data[i], column_widths)) + Style.RESET_ALL) if i == 0: - Util.print_line(length=sum(column_widths) + 5) - Util.print_line(length=sum(column_widths) + 5) + Util.print_line(length=sum(column_widths) + 5, stdio=stdio) + Util.print_line(length=sum(column_widths) + 5, stdio=stdio) @staticmethod def print_line(char='-', length=50, stdio=None): - print(char * length) + stdio.print(char * length) @staticmethod - def print_title(name, stdio=None): - print("\n[{0}]:".format(name)) + def print_title(name, stdio): + stdio.print("\n[{0}]:".format(name)) @staticmethod def gen_password(length=8, chars=string.ascii_letters + string.digits, stdio=None): diff --git a/core.py b/core.py index 969cfe46..a6ac8622 100644 --- a/core.py +++ b/core.py @@ -51,6 +51,7 @@ from handler.gather.gather_tabledump import GatherTableDumpHandler from handler.gather.gather_parameters import GatherParametersHandler from handler.gather.gather_variables import GatherVariablesHandler +from stdio import SafeStdio from telemetry.telemetry import telemetry from update.update import UpdateHandler from colorama import Fore, Style @@ -60,11 +61,11 @@ from common.tool import TimeUtils -class ObdiagHome(object): +class ObdiagHome(SafeStdio): def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config.yml'), inner_config_change_map=None): self._optimize_manager = None - self.stdio = None + self.stdio = stdio self._stdio_func = None self.cmds = [] self.options = Values() @@ -114,7 +115,7 @@ def set_stdio(self, stdio): def _print(msg, *arg, **kwarg): sep = kwarg['sep'] if 'sep' in kwarg else None end = kwarg['end'] if 'end' in kwarg else None - return print(msg, sep='' if sep is None else sep, end='\n' if end is None else end) + return stdio.print(msg, sep='' if sep is None else sep, end='\n' if end is None else end) self.stdio = stdio self._stdio_func = {} diff --git a/handler/checker/check_list.py b/handler/checker/check_list.py index 03e405cf..668e612d 100644 --- a/handler/checker/check_list.py +++ b/handler/checker/check_list.py @@ -74,8 +74,8 @@ def handle(self): "info_en": package_file_data[package_data].get("info_en") or "", "info_cn": package_file_data[package_data].get("info_cn") or "", } - Util.print_title("check cases about {0}".format(target)) - Util.print_scene(cases_map) + Util.print_title("check cases about {0}".format(target), stdio=self.stdio) + Util.print_scene(cases_map, stdio=self.stdio) return ObdiagResult(ObdiagResult.SUCCESS_CODE, result_map) except Exception as e: return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data=str(e)) diff --git a/handler/gather/scenes/list.py b/handler/gather/scenes/list.py index d4a970cf..0af2d06b 100644 --- a/handler/gather/scenes/list.py +++ b/handler/gather/scenes/list.py @@ -119,15 +119,15 @@ def print_scene_data(self): if self.other_tasks: sorted_other_tasks = sorted(self.other_tasks.items(), key=lambda x: x[0]) sorted_other_tasks_dict = {k: v for k, v in sorted_other_tasks} - Util.print_title("Other Problem Gather Scenes") - Util.print_scene(sorted_other_tasks_dict) + Util.print_title("Other Problem Gather Scenes", stdio=self.stdio) + Util.print_scene(sorted_other_tasks_dict, stdio=self.stdio) if self.obproxy_tasks: sorted_obproxy_tasks = sorted(self.obproxy_tasks.items(), key=lambda x: x[0]) sorted_obproxy_tasks_dict = {k: v for k, v in sorted_obproxy_tasks} - Util.print_title("Obproxy Problem Gather Scenes") - Util.print_scene(sorted_obproxy_tasks_dict) + Util.print_title("Obproxy Problem Gather Scenes", stdio=self.stdio) + Util.print_scene(sorted_obproxy_tasks_dict, stdio=self.stdio) if self.observer_tasks: sorted_observer_tasks = sorted(self.observer_tasks.items(), key=lambda x: x[0]) sorted_observer_tasks_dict = {k: v for k, v in sorted_observer_tasks} - Util.print_title("Observer Problem Gather Scenes") - Util.print_scene(sorted_observer_tasks_dict) + Util.print_title("Observer Problem Gather Scenes", stdio=self.stdio) + Util.print_scene(sorted_observer_tasks_dict, stdio=self.stdio) diff --git a/handler/rca/rca_list.py b/handler/rca/rca_list.py index 71b94be4..5df2cecc 100644 --- a/handler/rca/rca_list.py +++ b/handler/rca/rca_list.py @@ -62,7 +62,7 @@ def handle(self): try: self.stdio.verbose("list rca scenes") scene_info_list, scene_itme_list = self.get_all_scenes() - Util.print_scene(scene_info_list) + Util.print_scene(scene_info_list, stdio=self.stdio) except Exception as e: self.stdio.error("RcaScenesListHandler Exception: {0}".format(e)) raise e diff --git a/stdio.py b/stdio.py index bdb10105..81262e6f 100644 --- a/stdio.py +++ b/stdio.py @@ -359,7 +359,8 @@ class IO(object): WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout): + def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout, print_type=""): + self.print_type = "just_json" self.level = level self.msg_lv = msg_lv self.default_confirm = False @@ -718,7 +719,8 @@ def _print(self, msg_lv, msg, *args, **kwargs): kwargs['file'] = self.get_cur_err_obj() else: kwargs['file'] = self.get_cur_out_obj() - kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + if self.print_type != "just_json": + kwargs['file'] and print(self._format(print_msg, *args), **kwargs) del kwargs['file'] self.log(msg_lv, msg, *args, **kwargs) From a74175ab874f5ae73497249588591dc9e2262866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 7 Aug 2024 20:32:08 +0800 Subject: [PATCH 17/35] test --- diag_cmd.py | 3 +-- stdio.py | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/diag_cmd.py b/diag_cmd.py index e7265d1f..27f44527 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -272,8 +272,7 @@ def do_command(self): if self.has_trace: ROOT_IO.print('Trace ID: %s' % self.trace_id) ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, self.trace_id)) - return ret or ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) - + ROOT_IO.just_json(ret or ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."})) except NotImplementedError: ROOT_IO.exception('command \'%s\' is not implemented' % self.prev_cmd) except SystemExit: diff --git a/stdio.py b/stdio.py index 81262e6f..3b02b66c 100644 --- a/stdio.py +++ b/stdio.py @@ -350,6 +350,7 @@ class MsgLevel(object): DEBUG = 10 VERBOSE = DEBUG NOTSET = 0 + JUST_JSON = 60 class IO(object): @@ -721,6 +722,9 @@ def _print(self, msg_lv, msg, *args, **kwargs): kwargs['file'] = self.get_cur_out_obj() if self.print_type != "just_json": kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + else: + if msg_lv>=MsgLevel.JUST_JSON: + print(json.dumps(msg)) del kwargs['file'] self.log(msg_lv, msg, *args, **kwargs) @@ -750,6 +754,9 @@ def _log(self, levelno, msg, *args, **kwargs): def print(self, msg, *args, **kwargs): self._print(MsgLevel.INFO, msg, *args, **kwargs) + def just_json(self, msg, *args, **kwargs): + self._print(MsgLevel.JUST_JSON, msg, *args, **kwargs) + def warn(self, msg, *args, **kwargs): self._print(MsgLevel.WARN, msg, prev_msg=self.WARNING_PREV.format(self.isatty()), *args, **kwargs) From 5a1b50738a8d898d5553d23dccd4363751756c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 9 Aug 2024 17:49:37 +0800 Subject: [PATCH 18/35] test --- .github/workflows/build_package.yml | 1 + common/command.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_package.yml b/.github/workflows/build_package.yml index 6287fa6e..e3204857 100644 --- a/.github/workflows/build_package.yml +++ b/.github/workflows/build_package.yml @@ -7,6 +7,7 @@ on: push: branches: - master + - 2.4.0-fix-get_obproxy_version env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true diff --git a/common/command.py b/common/command.py index 4677e2e1..8d838198 100644 --- a/common/command.py +++ b/common/command.py @@ -286,7 +286,8 @@ def get_obproxy_version(context): obproxy_version_info = ssh_client.exec_cmd(cmd) stdio.verbose("get obproxy version, run cmd = [{0}] ".format(cmd)) if obproxy_version_info is not None: - ob_version = re.findall(r'[(]OceanBase.(.+? +?)[)]', obproxy_version_info) + pattern = r"(\d+\.\d+\.\d+\.\d+)" + ob_version = re.findall(pattern, obproxy_version_info) if len(ob_version) > 0: return ob_version[0] else: @@ -295,7 +296,6 @@ def get_obproxy_version(context): stdio.verbose("get obproxy version with LD_LIBRARY_PATH,cmd:{0}, result:{1}".format(cmd, obproxy_version_info)) if "REVISION" not in obproxy_version_info: raise Exception("Please check conf about proxy,{0}".format(obproxy_version_info)) - pattern = r"(\d+\.\d+\.\d+\.\d+)" match = re.search(pattern, obproxy_version_info) if match: obproxy_version_info = match.group(1) From 8e251cf6eca892c69f1cad2f88dc50ad4fc3a506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 12 Aug 2024 15:04:26 +0800 Subject: [PATCH 19/35] add new io buffer --- stdio.py | 92 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/stdio.py b/stdio.py index 3b02b66c..b9fa9351 100644 --- a/stdio.py +++ b/stdio.py @@ -84,6 +84,13 @@ def flush(self): return True +class SetBufferIO(BufferIO): + + def write(self, s): + if s not in self._buffer: + return super(SetBufferIO, self).write(s) + + class SysStdin(object): NONBLOCK = False @@ -147,6 +154,7 @@ def _readline(cls): try: for line in sys.stdin: return line + return '' except IOError: return '' finally: @@ -350,7 +358,6 @@ class MsgLevel(object): DEBUG = 10 VERBOSE = DEBUG NOTSET = 0 - JUST_JSON = 60 class IO(object): @@ -360,8 +367,8 @@ class IO(object): WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout, print_type=""): - self.print_type = "just_json" + def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout, silent=False): + self.silent = silent self.level = level self.msg_lv = msg_lv self.default_confirm = False @@ -382,6 +389,7 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self._before_critical = None self._output_is_tty = False self._input_is_tty = False + self._exit_buffer = SetBufferIO() self.set_input_stream(input_stream) self.set_output_stream(output_stream) self.set_err_stream(error_stream) @@ -490,8 +498,20 @@ def before_close(self): except: pass + @property + def exit_msg(self): + return self._exit_msg + + @exit_msg.setter + def exit_msg(self, msg): + self._exit_msg = msg + def _close(self): self.before_close() + self._flush_cache() + if self.exit_msg: + self.print(self.exit_msg) + self.exit_msg = "" self._flush_log() def __del__(self): @@ -519,7 +539,7 @@ def _cache_off(self): self._flush_log() self._log_cache = None return True - + def get_input_stream(self): if self._root_io: return self._root_io.get_input_stream() @@ -535,6 +555,11 @@ def get_cur_out_obj(self): return self._root_io.get_cur_out_obj() return self._cur_out_obj + def get_exit_buffer(self): + if self._root_io: + return self._root_io.get_exit_buffer() + return self._exit_buffer + def _start_buffer_io(self): if self._root_io: return False @@ -679,15 +704,18 @@ def print_list(self, ary, field_names=None, exp=lambda x: x if isinstance(x, (li def read(self, msg='', blocked=False): if msg: - self._print(MsgLevel.INFO, msg) - return self.get_input_stream().read(blocked) + if self.syncing: + self.verbose(msg, end='') + else: + self._print(MsgLevel.INFO, msg, end='') + return self.get_input_stream().readline(not self.syncing and blocked) def confirm(self, msg): - msg = '%s [y/n]: ' % msg - self.print(msg, end='') if self.default_confirm: - self.verbose("default confirm: True") + self.verbose("%s and then auto confirm yes" % msg) return True + msg = '%s [y/n]: ' % msg + self.print(msg, end='') if self.isatty() and not self.syncing: while True: try: @@ -699,6 +727,7 @@ def confirm(self, msg): except Exception as e: if not e: return False + self.print(msg, end='') else: self.verbose("isatty: %s, syncing: %s, auto confirm: False" % (self.isatty(), self.syncing)) return False @@ -716,17 +745,25 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - if msg_lv == MsgLevel.ERROR: - kwargs['file'] = self.get_cur_err_obj() + + if kwargs.get('_on_exit'): + kwargs['file'] = self.get_exit_buffer() + del kwargs['_on_exit'] else: - kwargs['file'] = self.get_cur_out_obj() - if self.print_type != "just_json": - kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + if msg_lv == MsgLevel.ERROR: + kwargs['file'] = self.get_cur_err_obj() + else: + kwargs['file'] = self.get_cur_out_obj() + + if '_disable_log' in kwargs: + enaable_log = not kwargs['_disable_log'] + del kwargs['_disable_log'] else: - if msg_lv>=MsgLevel.JUST_JSON: - print(json.dumps(msg)) + enaable_log = True + + kwargs['file'] and print(self._format(print_msg, *args), **kwargs) del kwargs['file'] - self.log(msg_lv, msg, *args, **kwargs) + enaable_log and self.log(msg_lv, msg, *args, **kwargs) def log(self, levelno, msg, *args, **kwargs): self._cache_log(levelno, msg, *args, **kwargs) @@ -750,6 +787,12 @@ def _flush_log(self): def _log(self, levelno, msg, *args, **kwargs): if self.trace_logger: self.trace_logger.log(levelno, msg, *args, **kwargs) + + def _flush_cache(self): + if not self._root_io: + text = self._exit_buffer.read() + if text: + self.print(text, _disable_log=True) def print(self, msg, *args, **kwargs): self._print(MsgLevel.INFO, msg, *args, **kwargs) @@ -790,14 +833,12 @@ def print_result_json(self, result): pass if sys.version_info.major == 2: - def exception(self, msg='', *args, **kwargs): import linecache - exception_msg = [] ei = sys.exc_info() exception_msg.append('Traceback (most recent call last):') - stack = traceback.extract_stack()[self.track_limit : -2] + stack = traceback.extract_stack()[self.track_limit:-2] tb = ei[2] while tb is not None: f = tb.tb_frame @@ -811,8 +852,7 @@ def exception(self, msg='', *args, **kwargs): stack.append((filename, lineno, name, line)) for line in stack: exception_msg.append(' File "%s", line %d, in %s' % line[:3]) - if line[3]: - exception_msg.append(' ' + line[3].strip()) + if line[3]: exception_msg.append(' ' + line[3].strip()) lines = [] for line in traceback.format_exception_only(ei[0], ei[1]): lines.append(line) @@ -824,13 +864,11 @@ def exception(self, msg='', *args, **kwargs): print_stack = lambda m: self.log(MsgLevel.ERROR, m) msg and self.error(msg) print_stack('\n'.join(exception_msg)) - else: - def exception(self, msg='', *args, **kwargs): ei = sys.exc_info() traceback_e = traceback.TracebackException(type(ei[1]), ei[1], ei[2], limit=None) - pre_stach = traceback.extract_stack()[self.track_limit : -2] + pre_stach = traceback.extract_stack()[self.track_limit:-2] pre_stach.reverse() for summary in pre_stach: traceback_e.stack.insert(0, summary) @@ -885,7 +923,7 @@ def __getattr__(self, item): if attr is not EMPTY: self._attrs[item] = attr else: - is_tty = getattr(self._stream, 'isatty', lambda: False)() + is_tty = getattr(self._stream, 'isatty', lambda : False)() self._warn_func(FormtatText.warning("WARNING: {} has no attribute '{}'".format(self.io, item)).format(is_tty)) self._attrs[item] = FAKE_RETURN return self._attrs[item] @@ -930,11 +968,9 @@ def func_wrapper(*args, **kwargs): stdio = get_stdio(kwargs.get("stdio", _default_stdio)) kwargs["stdio"] = stdio return func(*args, **kwargs) - return _type(func_wrapper) if is_bond_method else func_wrapper else: return _type(func) if is_bond_method else func - return decorated From 39ce3a1c407786de0f7b4cccb7247aff36d1b8bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 12 Aug 2024 20:38:01 +0800 Subject: [PATCH 20/35] add new io buffer --- conf/inner_config.yml | 1 + config.py | 1 + core.py | 5 +- .../checker/tasks/observer/bugs/bug_385.yaml | 14 +++++ handler/rca/scene/lock_conflict_scene.py | 4 +- stdio.py | 52 ++++++++++++------- 6 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 handler/checker/tasks/observer/bugs/bug_385.yaml diff --git a/conf/inner_config.yml b/conf/inner_config.yml index db4aa329..f241ba73 100644 --- a/conf/inner_config.yml +++ b/conf/inner_config.yml @@ -13,6 +13,7 @@ obdiag: mode: obdiag stdout_handler_log_level: INFO error_stream: sys.stdout + silent: false ssh_client: remote_client_sudo: 0 check: diff --git a/config.py b/config.py index cc2fc19f..bd32cbbe 100644 --- a/config.py +++ b/config.py @@ -74,6 +74,7 @@ 'mode': 'obdiag', 'stdout_handler_log_level': 'INFO', 'error_stream': 'sys.stdout', + 'silent': False, }, 'ssh_client': { 'remote_client_sudo': False, diff --git a/core.py b/core.py index a6ac8622..98e17cf7 100644 --- a/core.py +++ b/core.py @@ -73,9 +73,12 @@ def __init__(self, stdio=None, config_path=os.path.expanduser('~/.obdiag/config. self.set_stdio(stdio) self.context = None self.inner_config_manager = InnerConfigManager(stdio=stdio, inner_config_change_map=inner_config_change_map) + # obdiag.logger.error_stream if self.inner_config_manager.config.get("obdiag") is not None and self.inner_config_manager.config.get("obdiag").get("basic") is not None and self.inner_config_manager.config.get("obdiag").get("basic").get("print_type") is not None: stdio.set_err_stream(self.inner_config_manager.config.get("obdiag").get("logger").get("error_stream")) - + # obdiag.logger.silent + if self.inner_config_manager.config.get("obdiag") is not None and self.inner_config_manager.config.get("obdiag").get("logger") is not None and self.inner_config_manager.config.get("obdiag").get("logger").get("silent") is not None: + stdio.set_silent(self.inner_config_manager.config.get("obdiag").get("logger").get("silent")) self.set_stdio(stdio) if config_path: if os.path.exists(os.path.abspath(config_path)): diff --git a/handler/checker/tasks/observer/bugs/bug_385.yaml b/handler/checker/tasks/observer/bugs/bug_385.yaml new file mode 100644 index 00000000..255a5ece --- /dev/null +++ b/handler/checker/tasks/observer/bugs/bug_385.yaml @@ -0,0 +1,14 @@ +info: "OB version [4.2.1.0,4.2.1.3] If tenants have multiple root users. Please consider upgrading the OceanBase version or removing the redundant users. github issue #385" +task: + - version: "[4.2.1.0,4.2.1.3]" + steps: + - type: sql + sql: "SELECT GROUP_CONCAT(TENANT_ID) AS TENANT_ID +FROM oceanbase.CDB_OB_USERS +WHERE USER_NAME = 'root' +GROUP BY TENANT_ID +HAVING COUNT(*) > 1;" + result: + set_value: TENANT_ID + verify: '[ -z "$TENANT_ID" ]' + err_msg: "tenant: #{$TENANT_ID}. These tenants have multiple root users. Please consider upgrading the OceanBase version or removing the redundant users. Please get bug's on https://github.com/oceanbase/obdiag/issues/385" diff --git a/handler/rca/scene/lock_conflict_scene.py b/handler/rca/scene/lock_conflict_scene.py index b5a1b5d0..f05095fe 100644 --- a/handler/rca/scene/lock_conflict_scene.py +++ b/handler/rca/scene/lock_conflict_scene.py @@ -68,7 +68,7 @@ def __execute_4_2(self): trans_record.add_record("get holding_lock trans_id:{0}".format(trans_id)) holding_lock_session_id = trans_id self.stdio.verbose("get holding lock SESSION_ID by trans_id:{0}".format(trans_id)) - cursor_by_trans_id = self.ob_connector.execute_sql_return_cursor_dictionary('select * from oceanbase.GV$OB_TRANSACTION_PARTICIPANTS where TX_ID="{0}";'.format(holding_lock_session_id)) + cursor_by_trans_id = self.ob_connector.execute_sql_return_cursor_dictionary('select * from oceanbase.GV$OB_TRANSACTION_PARTICIPANTS where TX_ID="{0}" and SESSION_ID<>0;'.format(holding_lock_session_id)) holding_lock_session_id_datas = cursor_by_trans_id.fetchall() holding_lock_session_id = "not get" self.stdio.verbose("get sql_info by holding_lock_session_id:{0}".format(holding_lock_session_id_datas)) @@ -82,7 +82,7 @@ def __execute_4_2(self): wait_lock_trans_id = OB_LOCKS_data["TRANS_ID"] trans_record.add_record("wait_lock_trans_id is {0}".format(wait_lock_trans_id)) - cursor_by_trans_id = self.ob_connector.execute_sql_return_cursor_dictionary('select * from oceanbase.GV$OB_TRANSACTION_PARTICIPANTS where TX_ID="{0}";'.format(wait_lock_trans_id)) + cursor_by_trans_id = self.ob_connector.execute_sql_return_cursor_dictionary('select * from oceanbase.GV$OB_TRANSACTION_PARTICIPANTS where TX_ID="{0}" and SESSION_ID<>0;'.format(wait_lock_trans_id)) wait_lock_session_datas = cursor_by_trans_id.fetchall() self.stdio.verbose("get sql_info by holding_lock_session_id:{0}".format(holding_lock_session_id)) diff --git a/stdio.py b/stdio.py index b9fa9351..ffebb918 100644 --- a/stdio.py +++ b/stdio.py @@ -358,6 +358,7 @@ class MsgLevel(object): DEBUG = 10 VERBOSE = DEBUG NOTSET = 0 + SILENT = 60 class IO(object): @@ -387,6 +388,7 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self._cur_out_obj = None self._cur_err_obj = None self._before_critical = None + self._exit_msg = "" self._output_is_tty = False self._input_is_tty = False self._exit_buffer = SetBufferIO() @@ -394,6 +396,9 @@ def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, self.set_output_stream(output_stream) self.set_err_stream(error_stream) + def set_silent(self, silent=False): + self.silent = bool(silent) + def isatty(self): if self._root_io: return self._root_io.isatty() @@ -539,7 +544,7 @@ def _cache_off(self): self._flush_log() self._log_cache = None return True - + def get_input_stream(self): if self._root_io: return self._root_io.get_input_stream() @@ -745,7 +750,8 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - + if self.silent: + kwargs['_on_exit'] = True if kwargs.get('_on_exit'): kwargs['file'] = self.get_exit_buffer() del kwargs['_on_exit'] @@ -754,14 +760,22 @@ def _print(self, msg_lv, msg, *args, **kwargs): kwargs['file'] = self.get_cur_err_obj() else: kwargs['file'] = self.get_cur_out_obj() - if '_disable_log' in kwargs: enaable_log = not kwargs['_disable_log'] del kwargs['_disable_log'] else: enaable_log = True - - kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + if self.silent: + if msg_lv == MsgLevel.SILENT: + kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + else: + # when silent is True, only print MsgLevel.SILENT + pass + else: + if msg_lv == MsgLevel.SILENT: + pass + else: + kwargs['file'] and print(self._format(print_msg, *args), **kwargs) del kwargs['file'] enaable_log and self.log(msg_lv, msg, *args, **kwargs) @@ -787,7 +801,7 @@ def _flush_log(self): def _log(self, levelno, msg, *args, **kwargs): if self.trace_logger: self.trace_logger.log(levelno, msg, *args, **kwargs) - + def _flush_cache(self): if not self._root_io: text = self._exit_buffer.read() @@ -822,23 +836,18 @@ def verbose(self, msg, *args, **kwargs): return self._print(MsgLevel.VERBOSE, '%s %s' % (self._verbose_prefix, msg), *args, **kwargs) - def print_result_json(self, result): - - if not result: - return - if isinstance(result, dict): - result = json.dumps(result, indent=4) - self.print(result) - - pass + def silent_print(self, msg, *args, **kwargs): + self._print(MsgLevel.SILENT, msg, *args, **kwargs) if sys.version_info.major == 2: + def exception(self, msg='', *args, **kwargs): import linecache + exception_msg = [] ei = sys.exc_info() exception_msg.append('Traceback (most recent call last):') - stack = traceback.extract_stack()[self.track_limit:-2] + stack = traceback.extract_stack()[self.track_limit : -2] tb = ei[2] while tb is not None: f = tb.tb_frame @@ -852,7 +861,8 @@ def exception(self, msg='', *args, **kwargs): stack.append((filename, lineno, name, line)) for line in stack: exception_msg.append(' File "%s", line %d, in %s' % line[:3]) - if line[3]: exception_msg.append(' ' + line[3].strip()) + if line[3]: + exception_msg.append(' ' + line[3].strip()) lines = [] for line in traceback.format_exception_only(ei[0], ei[1]): lines.append(line) @@ -864,11 +874,13 @@ def exception(self, msg='', *args, **kwargs): print_stack = lambda m: self.log(MsgLevel.ERROR, m) msg and self.error(msg) print_stack('\n'.join(exception_msg)) + else: + def exception(self, msg='', *args, **kwargs): ei = sys.exc_info() traceback_e = traceback.TracebackException(type(ei[1]), ei[1], ei[2], limit=None) - pre_stach = traceback.extract_stack()[self.track_limit:-2] + pre_stach = traceback.extract_stack()[self.track_limit : -2] pre_stach.reverse() for summary in pre_stach: traceback_e.stack.insert(0, summary) @@ -923,7 +935,7 @@ def __getattr__(self, item): if attr is not EMPTY: self._attrs[item] = attr else: - is_tty = getattr(self._stream, 'isatty', lambda : False)() + is_tty = getattr(self._stream, 'isatty', lambda: False)() self._warn_func(FormtatText.warning("WARNING: {} has no attribute '{}'".format(self.io, item)).format(is_tty)) self._attrs[item] = FAKE_RETURN return self._attrs[item] @@ -968,9 +980,11 @@ def func_wrapper(*args, **kwargs): stdio = get_stdio(kwargs.get("stdio", _default_stdio)) kwargs["stdio"] = stdio return func(*args, **kwargs) + return _type(func_wrapper) if is_bond_method else func_wrapper else: return _type(func) if is_bond_method else func + return decorated From 769418f281b08d5668b9f998a85cc853ea1e6e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 13 Aug 2024 10:57:15 +0800 Subject: [PATCH 21/35] build test package --- .github/workflows/build_package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_package.yml b/.github/workflows/build_package.yml index e3204857..4aacc390 100644 --- a/.github/workflows/build_package.yml +++ b/.github/workflows/build_package.yml @@ -7,7 +7,7 @@ on: push: branches: - master - - 2.4.0-fix-get_obproxy_version + - 2.4.0-silent-print env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true From 7ecfdcd443941b7eb25bd41ee92b3b8951174780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 13 Aug 2024 11:31:28 +0800 Subject: [PATCH 22/35] silent change --- stdio.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/stdio.py b/stdio.py index ffebb918..dc09820d 100644 --- a/stdio.py +++ b/stdio.py @@ -358,7 +358,6 @@ class MsgLevel(object): DEBUG = 10 VERBOSE = DEBUG NOTSET = 0 - SILENT = 60 class IO(object): @@ -367,6 +366,7 @@ class IO(object): VERBOSE_LEVEL = 0 WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') + # The silent flag is used as a marker to indicate whether the msg is printed on the stream. If it is true, it will not be output to the steam def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout, silent=False): self.silent = silent @@ -750,8 +750,6 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['prev_msg'] else: print_msg = msg - if self.silent: - kwargs['_on_exit'] = True if kwargs.get('_on_exit'): kwargs['file'] = self.get_exit_buffer() del kwargs['_on_exit'] @@ -765,17 +763,11 @@ def _print(self, msg_lv, msg, *args, **kwargs): del kwargs['_disable_log'] else: enaable_log = True + # if self.silent is True, Not print to stream if self.silent: - if msg_lv == MsgLevel.SILENT: - kwargs['file'] and print(self._format(print_msg, *args), **kwargs) - else: - # when silent is True, only print MsgLevel.SILENT - pass + pass else: - if msg_lv == MsgLevel.SILENT: - pass - else: - kwargs['file'] and print(self._format(print_msg, *args), **kwargs) + kwargs['file'] and print(self._format(print_msg, *args), **kwargs) del kwargs['file'] enaable_log and self.log(msg_lv, msg, *args, **kwargs) @@ -811,9 +803,6 @@ def _flush_cache(self): def print(self, msg, *args, **kwargs): self._print(MsgLevel.INFO, msg, *args, **kwargs) - def just_json(self, msg, *args, **kwargs): - self._print(MsgLevel.JUST_JSON, msg, *args, **kwargs) - def warn(self, msg, *args, **kwargs): self._print(MsgLevel.WARN, msg, prev_msg=self.WARNING_PREV.format(self.isatty()), *args, **kwargs) @@ -836,9 +825,6 @@ def verbose(self, msg, *args, **kwargs): return self._print(MsgLevel.VERBOSE, '%s %s' % (self._verbose_prefix, msg), *args, **kwargs) - def silent_print(self, msg, *args, **kwargs): - self._print(MsgLevel.SILENT, msg, *args, **kwargs) - if sys.version_info.major == 2: def exception(self, msg='', *args, **kwargs): From ec8d4a8302664d7a4cadad2d494e3d8d9f1c06d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 13 Aug 2024 15:11:31 +0800 Subject: [PATCH 23/35] delete init.sh cp gather dir more --- init.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/init.sh b/init.sh index 766b82d5..3b9bde96 100755 --- a/init.sh +++ b/init.sh @@ -25,10 +25,6 @@ if [ -d "${WORK_DIR}/gather" ]; then cp -rf ${WORK_DIR}/gather ${OBDIAG_HOME}/ fi -if [ -d "${WORK_DIR}/gather" ]; then - cp -rf ${WORK_DIR}/gather ${OBDIAG_HOME}/ -fi - if [ -d "${WORK_DIR}/example" ]; then cp -rf ${WORK_DIR}/example ${OBDIAG_HOME}/ fi @@ -37,7 +33,6 @@ if [ -d "${WORK_DIR}/rca" ]; then cp -rf ${WORK_DIR}/rca ${OBDIAG_HOME}/ fi - ALIAS_OBDIAG_EXIST=$(grep "alias obdiag='sh" ~/.bashrc | head -n 1) if [[ "${ALIAS_OBDIAG_EXIST}" != "" ]]; then echo "need update obdiag alias" From 8fc9a51032c0e0d2b0cb2c14067ba401211e6e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 14:58:00 +0800 Subject: [PATCH 24/35] update --- config.py | 17 +++++++++- core.py | 45 +++++++++++++++------------ diag_cmd.py | 12 +++++-- handler/analyzer/analyze_flt_trace.py | 13 +++++--- handler/analyzer/analyze_log.py | 11 +++++-- handler/analyzer/analyze_parameter.py | 19 +++++++---- handler/analyzer/analyze_sql.py | 9 +++--- handler/analyzer/analyze_variable.py | 10 ++++-- handler/checker/check_list.py | 2 +- handler/gather/gather_ash_report.py | 5 +-- handler/rca/rca_handler.py | 13 +++++++- handler/rca/rca_list.py | 4 ++- result_type.py | 29 ++++++++++++----- update/update.py | 31 +++++++++++------- 14 files changed, 152 insertions(+), 68 deletions(-) diff --git a/config.py b/config.py index c3aa9ce1..bd32cbbe 100644 --- a/config.py +++ b/config.py @@ -262,7 +262,22 @@ def get_node_config(self, type, node_ip, config_item): class InnerConfigManager(Manager): - def __init__(self, stdio=None): + def __init__(self, stdio=None, inner_config_change_map=None): + if inner_config_change_map is None: + inner_config_change_map = {} inner_config_abs_path = os.path.abspath(INNER_CONFIG_FILE) super().__init__(inner_config_abs_path, stdio=stdio) self.config = self.load_config_with_defaults(DEFAULT_INNER_CONFIG) + if inner_config_change_map != {}: + self.config = self._change_inner_config(self.config, inner_config_change_map) + + def _change_inner_config(self, conf_map, change_conf_map): + for key, value in change_conf_map.items(): + if key in conf_map: + if isinstance(value, dict): + self._change_inner_config(conf_map[key], value) + else: + conf_map[key] = value + else: + conf_map[key] = value + return conf_map diff --git a/core.py b/core.py index 4aa6cf92..ebb52df9 100644 --- a/core.py +++ b/core.py @@ -51,6 +51,7 @@ from handler.gather.gather_tabledump import GatherTableDumpHandler from handler.gather.gather_parameters import GatherParametersHandler from handler.gather.gather_variables import GatherVariablesHandler +from result_type import ObdiagResult from telemetry.telemetry import telemetry from update.update import UpdateHandler from colorama import Fore, Style @@ -200,7 +201,7 @@ def gather_function(self, function_type, opt): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.stdio.print("{0} start ...".format(function_type)) self.set_context(function_type, 'gather', config) @@ -267,7 +268,7 @@ def gather_obproxy_log(self, opt): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.set_context_skip_cluster_conn('gather_obproxy_log', 'gather', config) handler = GatherObProxyLogHandler(self.context) @@ -282,33 +283,34 @@ def analyze_fuction(self, function_type, opt): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.stdio.print("{0} start ...".format(function_type)) if function_type == 'analyze_log': self.set_context(function_type, 'analyze', config) handler = AnalyzeLogHandler(self.context) - handler.handle() + return handler.handle() elif function_type == 'analyze_log_offline': self.set_context_skip_cluster_conn(function_type, 'analyze', config) handler = AnalyzeLogHandler(self.context) - handler.handle() + return handler.handle() elif function_type == 'analyze_flt_trace': self.set_context(function_type, 'analyze', config) handler = AnalyzeFltTraceHandler(self.context) - handler.handle() + return handler.handle() elif function_type == 'analyze_parameter_default': self.set_context(function_type, 'analyze', config) handler = AnalyzeParameterHandler(self.context, 'default') - handler.handle() + return handler.handle() elif function_type == 'analyze_parameter_diff': self.set_context_skip_cluster_conn(function_type, 'analyze', config) handler = AnalyzeParameterHandler(self.context, 'diff') - handler.handle() + return handler.handle() elif function_type == 'analyze_variable_diff': self.set_context(function_type, 'analyze', config) handler = AnalyzeVariableHandler(self.context, 'diff') - handler.handle() + return handler.handle() + # todo not support silent elif function_type == 'analyze_sql': self.set_context(function_type, 'analyze', config) handler = AnalyzeSQLHandler(self.context) @@ -319,13 +321,13 @@ def analyze_fuction(self, function_type, opt): handler.handle() else: self._call_stdio('error', 'Not support analyze function: {0}'.format(function_type)) - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='Not support analyze function: {0}'.format(function_type)) def check(self, opts): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.stdio.print("check start ...") self.set_context('check', 'check', config) @@ -347,59 +349,62 @@ def check(self, opts): observer_report_path = os.path.expanduser(observer_check_handler.report.get_report_path()) if os.path.exists(observer_report_path): self.stdio.print("Check observer finished. For more details, please run cmd'" + Fore.YELLOW + " cat {0} ".format(observer_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={}) def check_list(self, opts): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.set_offline_context('check_list', 'check_list') handler = CheckListHandler(self.context) - handler.handle() + return handler.handle() def rca_run(self, opts): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.set_context('rca_run', 'rca_run', config) try: handler = RCAHandler(self.context) handler.handle() - handler.execute() + return handler.execute() except Exception as e: self.stdio.error("rca run Exception: {0}".format(e)) self.stdio.verbose(traceback.format_exc()) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="rca run Exception: {0}".format(e)) def rca_list(self, opts): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.set_offline_context('rca_list', 'rca_list') handler = RcaScenesListHandler(context=self.context) - handler.handle() + return handler.handle() def update(self, opts): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.stdio.print("update start ...") self.set_offline_context('update', 'update') handler = UpdateHandler(self.context) - handler.execute() + return handler.execute() def config(self, opt): config = self.config_manager if not config: self._call_stdio('error', 'No such custum config') - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='No such custum config') else: self.set_offline_context('config', 'config') config_helper = ConfigHelper(context=self.context) config_helper.build_configuration() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"msg": "config success"}) diff --git a/diag_cmd.py b/diag_cmd.py index 7803fbca..5af3bc2a 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -273,13 +273,19 @@ def do_command(self): obdiag.set_cmds(self.cmds) ret = self._do_command(obdiag) if isinstance(ret, ObdiagResult) is False: - ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) - return + ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) + ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) ret.set_trace_id(self.trace_id) - telemetry.put_data() + ret.set_command(self.prev_cmd) + # if silent is true ,print ret + if ROOT_IO.silent: + ROOT_IO.set_silent(False) + ROOT_IO.print(ret.get_result()) + ROOT_IO.set_silent(True) if self.has_trace: ROOT_IO.print('Trace ID: %s' % self.trace_id) ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, self.trace_id)) + telemetry.put_data() except NotImplementedError: ROOT_IO.exception('command \'%s\' is not implemented' % self.prev_cmd) except SystemExit: diff --git a/handler/analyzer/analyze_flt_trace.py b/handler/analyzer/analyze_flt_trace.py index cac530a1..8d9dff6b 100644 --- a/handler/analyzer/analyze_flt_trace.py +++ b/handler/analyzer/analyze_flt_trace.py @@ -28,6 +28,7 @@ from common.tool import Util from common.tool import DirectoryUtil from common.tool import FileUtil +from result_type import ObdiagResult class AnalyzeFltTraceHandler(object): @@ -86,10 +87,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data='init option failed') if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data='init config failed') local_store_parent_dir = os.path.join(self.gather_pack_dir, "obdiag_analyze_flt_result_{0}".format(TimeUtils.timestamp_to_filename_time(self.gather_timestamp))) self.stdio.verbose("Use {0} as pack dir.".format(local_store_parent_dir)) analyze_tuples = [] @@ -119,8 +120,7 @@ def handle_from_node(node): data = future.result() tree.build(data) # output tree - self.__output(local_store_parent_dir, tree, self.output) - return analyze_tuples + return self.__output(local_store_parent_dir, tree, self.output) def __handle_from_node(self, node, old_files, local_store_parent_dir): resp = {"skip": False, "error": ""} @@ -346,6 +346,11 @@ def __output(self, result_dir, tree, output_terminal=60): self.stdio.verbose('Result saved: {}'.format(os.path.abspath(filename))) last_info = "For more details, please run cmd \033[32m' cat {0} '\033[0m\n".format(filename) self.stdio.print(last_info) + result_info = "" + with open(filename, 'r', encoding='utf-8') as f: + for line in f: + result_info += line + return result_info def parse_file(self, file): self.stdio.verbose('parse file: {}'.format(file[1])) diff --git a/handler/analyzer/analyze_log.py b/handler/analyzer/analyze_log.py index 439f7928..1794f480 100644 --- a/handler/analyzer/analyze_log.py +++ b/handler/analyzer/analyze_log.py @@ -32,6 +32,7 @@ from common.tool import FileUtil from common.tool import TimeUtils import common.ssh_client.local_client as ssh_client_local_client +from result_type import ObdiagResult class AnalyzeLogHandler(BaseShellHandler): @@ -125,10 +126,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") local_store_parent_dir = os.path.join(self.gather_pack_dir, "obdiag_analyze_pack_{0}".format(TimeUtils.timestamp_to_filename_time(TimeUtils.get_current_us_timestamp()))) self.stdio.verbose("Use {0} as pack dir.".format(local_store_parent_dir)) analyze_tuples = [] @@ -160,7 +161,11 @@ def handle_from_node(node): FileUtil.write_append(os.path.join(local_store_parent_dir, "result_details.txt"), field_names[n] + ": " + str(summary_details_list[m][n]) + extend) last_info = "For more details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(local_store_parent_dir, "result_details.txt")) self.stdio.print(last_info) - return analyze_tuples + # get info from local_store_parent_dir+/result_details.txt + analyze_info = "" + with open(os.path.join(local_store_parent_dir, "result_details.txt"), "r", encoding="utf-8") as f: + analyze_info = f.read() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": analyze_info}) def __handle_from_node(self, node, local_store_parent_dir): resp = {"skip": False, "error": ""} diff --git a/handler/analyzer/analyze_parameter.py b/handler/analyzer/analyze_parameter.py index 26c6c31a..f4db52a8 100644 --- a/handler/analyzer/analyze_parameter.py +++ b/handler/analyzer/analyze_parameter.py @@ -26,6 +26,8 @@ import datetime from colorama import Fore, Style +from result_type import ObdiagResult + class AnalyzeParameterHandler(object): def __init__(self, context, analyze_type='default'): @@ -67,14 +69,14 @@ def handle(self): if self.analyze_type == 'default': if not self.init_option_default(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") else: if not self.init_option_diff(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") self.stdio.verbose("Use {0} as pack dir.".format(self.export_report_path)) DirectoryUtil.mkdir(path=self.export_report_path, stdio=self.stdio) - self.execute() + return self.execute() def check_file_valid(self): with open(self.parameter_file_name, 'r') as f: @@ -167,10 +169,11 @@ def analyze_parameter_default(self): fp.write(report_default_tb.get_string() + "\n") self.stdio.print(report_default_tb.get_string()) self.stdio.print("Analyze parameter default finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(file_name) + Style.RESET_ALL + "'") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": report_default_tb.get_string(), "file_name": file_name}) else: if self.parameter_file_name is None: self.stdio.error("the version of OceanBase is lower than 4.2.2, an initialization parameter file must be provided to find non-default values") - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="the version of OceanBase is lower than 4.2.2, an initialization parameter file must be provided to find non-default values") else: sql = '''select substr(version(),8), svr_ip,svr_port,zone,scope,TENANT_ID,name,value,section, EDIT_LEVEL, now(),'','' from GV$OB_PARAMETERS order by 5,2,3,4,7''' @@ -262,6 +265,7 @@ def alalyze_parameter_diff(self): file_name = self.export_report_path + '/parameter_diff_{0}.table'.format(date_format) fp = open(file_name, 'a+', encoding="utf8") is_empty = True + report_diff_tbs = [] for tenant, value_list in diff_parameter_dict.items(): if len(value_list) > 0: report_diff_tb = PrettyTable(["name", "diff"]) @@ -279,17 +283,20 @@ def alalyze_parameter_diff(self): fp.write(report_diff_tb.get_string() + "\n") self.stdio.print(report_diff_tb.get_string()) is_empty = False + report_diff_tbs.append(report_diff_tb.get_string()) fp.close() if not is_empty: self.stdio.print("Analyze parameter diff finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(file_name) + Style.RESET_ALL + "'") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": report_diff_tbs, "file_name": file_name}) else: self.stdio.print("Analyze parameter diff finished. All parameter settings are consistent among observers") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": "Analyze parameter diff finished. All parameter settings are consistent among observers"}) def execute(self): try: if self.analyze_type == 'default': - self.analyze_parameter_default() + return self.analyze_parameter_default() elif self.analyze_type == 'diff': - self.alalyze_parameter_diff() + return self.alalyze_parameter_diff() except Exception as e: self.stdio.error("parameter info analyze failed, error message: {0}".format(e)) diff --git a/handler/analyzer/analyze_sql.py b/handler/analyzer/analyze_sql.py index e6ab6374..ded4f21b 100644 --- a/handler/analyzer/analyze_sql.py +++ b/handler/analyzer/analyze_sql.py @@ -30,6 +30,7 @@ from handler.analyzer.sql.meta.sys_tenant_meta import SysTenantMeta from handler.gather.gather_scenes import GatherSceneHandler from common.command import get_observer_version +from result_type import ObdiagResult class AnalyzeSQLHandler(object): @@ -208,16 +209,16 @@ def handle(self): self.start_time = time.time() if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_inner_config(): self.stdio.error('init inner config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init inner config failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") if not self.init_ob_version(): self.stdio.error('init ob version failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init ob version failed") self.init_db_connector() self.local_store_path = os.path.join(self.local_stored_parrent_path, "obdiag_analyze_sql_result_{0}_{1}.html".format(TimeUtils.timestamp_to_filename_time(self.from_timestamp), TimeUtils.timestamp_to_filename_time(self.to_timestamp))) self.stdio.print("use {0} as result store path.".format(self.local_store_path)) diff --git a/handler/analyzer/analyze_variable.py b/handler/analyzer/analyze_variable.py index e3bbc5d9..9199e77a 100644 --- a/handler/analyzer/analyze_variable.py +++ b/handler/analyzer/analyze_variable.py @@ -24,6 +24,8 @@ import datetime from colorama import Fore, Style +from result_type import ObdiagResult + class AnalyzeVariableHandler(object): def __init__(self, context, analyze_type='diff'): @@ -55,10 +57,10 @@ def __init__(self, context, analyze_type='diff'): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") self.stdio.verbose("Use {0} as pack dir.".format(self.export_report_path)) DirectoryUtil.mkdir(path=self.export_report_path, stdio=self.stdio) - self.execute() + return self.execute() def check_file_valid(self): with open(self.variable_file_name, 'r') as f: @@ -149,11 +151,13 @@ def analyze_variable(self): self.stdio.print(Fore.RED + "Since {0}, the following variables have changed:".format(last_gather_time) + Style.RESET_ALL) self.stdio.print(report_default_tb.get_string()) self.stdio.print("Analyze variables changed finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(file_name) + Style.RESET_ALL + "'") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": report_default_tb.get_string()}) else: self.stdio.print("Analyze variables changed finished. Since {0}, No changes in variables".format(last_gather_time)) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": "Since {0}, No changes in variables".format(last_gather_time)}) def execute(self): try: - self.analyze_variable() + return self.analyze_variable() except Exception as e: self.stdio.error("variable info analyze failed, error message: {0}".format(e)) diff --git a/handler/checker/check_list.py b/handler/checker/check_list.py index 668e612d..3a5c5d9d 100644 --- a/handler/checker/check_list.py +++ b/handler/checker/check_list.py @@ -76,6 +76,6 @@ def handle(self): } Util.print_title("check cases about {0}".format(target), stdio=self.stdio) Util.print_scene(cases_map, stdio=self.stdio) - return ObdiagResult(ObdiagResult.SUCCESS_CODE, result_map) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data=result_map) except Exception as e: return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data=str(e)) diff --git a/handler/gather/gather_ash_report.py b/handler/gather/gather_ash_report.py index fc1e4eb1..883e58fa 100644 --- a/handler/gather/gather_ash_report.py +++ b/handler/gather/gather_ash_report.py @@ -22,6 +22,7 @@ from common.ob_connector import OBConnector from common.obdiag_exception import OBDIAGFormatException, OBDIAGException from common.tool import DirectoryUtil, TimeUtils, Util, StringUtils +from result_type import ObdiagResult from stdio import SafeStdio from colorama import Fore, Style @@ -60,10 +61,10 @@ def __init__(self, context, gather_pack_dir='./'): def handle(self): if not self.version_check(): self.stdio.error('version check failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="version check failed") if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") self.__init_report_path() self.execute() self.__print_result() diff --git a/handler/rca/rca_handler.py b/handler/rca/rca_handler.py index 4699c37d..d72715eb 100644 --- a/handler/rca/rca_handler.py +++ b/handler/rca/rca_handler.py @@ -33,6 +33,8 @@ from common.tool import StringUtils from colorama import Fore, Style +from result_type import ObdiagResult + class RCAHandler: def __init__(self, context): @@ -173,7 +175,7 @@ def execute(self): self.rca_scene.execute() except RCANotNeedExecuteException as e: self.stdio.warn("rca_scene.execute not need execute: {0}".format(e)) - pass + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, data="rca_scene.execute not need execute: {0}") except Exception as e: raise Exception("rca_scene.execute err: {0}".format(e)) try: @@ -181,6 +183,7 @@ def execute(self): except Exception as e: raise Exception("rca_scene.export_result err: {0}".format(e)) self.stdio.print("rca finished. For more details, the result on '" + Fore.YELLOW + self.get_result_path() + Style.RESET_ALL + "' \nYou can get the suggest by '" + Fore.YELLOW + "cat " + self.get_result_path() + "/record" + Style.RESET_ALL + "'") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.get_result_path(), "record": self.rca_scene.records_data()}) class RcaScene: @@ -277,6 +280,14 @@ def export(self): f.write(record.export_suggest()) f.write("\n") + def records_data(self): + records_data = [] + for record in self.records: + if record.records is None or len(record.records) == 0: + continue + records_data.append({"record": record.records, "suggest": record.suggest}) + return records_data + class RCA_ResultRecord: def __init__(self, stdio=None): diff --git a/handler/rca/rca_list.py b/handler/rca/rca_list.py index 5df2cecc..bd6c3914 100644 --- a/handler/rca/rca_list.py +++ b/handler/rca/rca_list.py @@ -19,6 +19,7 @@ from common.constant import const from common.tool import DynamicLoading from common.tool import Util +from result_type import ObdiagResult class RcaScenesListHandler: @@ -63,9 +64,10 @@ def handle(self): self.stdio.verbose("list rca scenes") scene_info_list, scene_itme_list = self.get_all_scenes() Util.print_scene(scene_info_list, stdio=self.stdio) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data=scene_info_list) except Exception as e: self.stdio.error("RcaScenesListHandler Exception: {0}".format(e)) - raise e + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="RcaScenesListHandler Exception:".format(e)) def __find_rca_files(self): files = [] diff --git a/result_type.py b/result_type.py index 2d144b2a..c5755f5a 100644 --- a/result_type.py +++ b/result_type.py @@ -1,3 +1,6 @@ +import json + + class ObdiagResult: # ObdiagResult is the result of obdiag. # It contains the code and result of obdiag. @@ -10,6 +13,7 @@ class ObdiagResult: SUCCESS_CODE = 200 def __init__(self, code, data=None, error_data=None): + self.command = None self.trace_id = None self.data = data self.error_data = error_data @@ -19,14 +23,16 @@ def __init__(self, code, data=None, error_data=None): self.code = str(code) else: raise TypeError("ObdiagResult code is not int. Please contact the Oceanbase community. ") - if isinstance(data, dict): - self.result = data - else: - raise TypeError("ObdiagResult result is not str. Please contact the Oceanbase community. ") - if isinstance(error_data, str): - self.error_data = error_data - else: - raise TypeError("ObdiagResult error_data is not str. Please contact the Oceanbase community. ") + if data is not None: + if isinstance(data, dict): + self.result = data + else: + raise TypeError("ObdiagResult data is not dict. Please contact the Oceanbase community. ") + if error_data is not None: + if isinstance(error_data, str): + self.error_data = error_data + else: + raise TypeError("ObdiagResult error_data is not str. Please contact the Oceanbase community. ") def set_trace_id(self, trace_id): if trace_id is None: @@ -35,3 +41,10 @@ def set_trace_id(self, trace_id): self.trace_id = trace_id else: raise TypeError("ObdiagResult trace_id is not str. Please contact the Oceanbase community. ") + + def set_command(self, command): + self.command = command + + def get_result(self): + result = {"code": self.code, "data": self.result, "error_data": self.error_data, "trace_id": self.trace_id, "command": self.command} + return json.dumps(result) diff --git a/update/update.py b/update/update.py index 125a230b..a59b1117 100644 --- a/update/update.py +++ b/update/update.py @@ -26,6 +26,8 @@ from common.version import OBDIAG_VERSION import yaml +from result_type import ObdiagResult + # for update obdiag files without obdiag class UpdateHandler: @@ -55,17 +57,16 @@ def execute(self): local_update_file_name = os.path.expanduser('~/.obdiag/data.tar') local_update_log_file_name = os.path.expanduser('~/.obdiag/data_version.yaml') if file_path and file_path != "": - self.handle_update_offline(file_path) - return + return self.handle_update_offline(file_path) if NetUtils.network_connectivity(remote_server) is False: self.stdio.warn("[update] network connectivity failed. Please check your network connection.") - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "network connectivity failed. Please check your network connection."}) NetUtils.download_file(remote_version_file_name, os.path.expanduser(local_version_file_name)) with open(local_version_file_name, 'r') as file: remote_data = yaml.safe_load(file) if remote_data.get("obdiag_version") is None: self.stdio.warn("obdiag_version is None. Do not perform the upgrade process.") - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "obdiag_version is None. Do not perform the upgrade process."}) else: self.remote_obdiag_version = remote_data["obdiag_version"].strip() if StringUtils.compare_versions_greater(self.remote_obdiag_version, self.local_obdiag_version): @@ -74,10 +75,17 @@ def execute(self): "remote_obdiag_version>local_obdiag_version. Unable to update dependency files, please upgrade " "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version) ) - return + return ObdiagResult( + ObdiagResult.SERVER_ERROR_CODE, + error_data={ + "msg": "remote_obdiag_version is {0}. local_obdiag_version is {1}. " + "remote_obdiag_version>local_obdiag_version. Unable to update dependency files, please upgrade " + "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version) + }, + ) if remote_data.get("remote_tar_sha") is None: self.stdio.warn("remote_tar_sha is None. Do not perform the upgrade process.") - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "remote_tar_sha is None. Do not perform the upgrade process."}) else: self.remote_tar_sha = remote_data["remote_tar_sha"] # need update? @@ -88,7 +96,7 @@ def execute(self): local_data = yaml.safe_load(file) if local_data.get("remote_tar_sha") is not None and local_data.get("remote_tar_sha") == self.remote_tar_sha: self.stdio.warn("[update] remote_tar_sha as local_tar_sha. No need to update.") - return + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"msg": "remote_tar_sha as local_tar_sha. No need to update."}) # get data_update_time if local_data.get("data_update_time") is not None and time.time() - local_data["data_update_time"] < 3600 * 24 * 7: self.stdio.warn("[update] data_update_time No need to update.") @@ -123,9 +131,10 @@ def execute(self): with open(os.path.expanduser("~/.obdiag/data_version.yaml"), 'w') as f: yaml.dump({"data_update_time": int(time.time()), "remote_tar_sha": self.remote_tar_sha}, f) self.stdio.print("[update] Successfully updated. The original data is stored in the *. d folder.") - return + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"msg": "Successfully updated. The original data is stored in the *. d folder."}) except Exception as e: self.stdio.warn('[update] Failed to update. Error message: {0}'.format(e)) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="Failed to update. Error message: {0}".format(e)) def handle_update_offline(self, file): file = os.path.expanduser(file) @@ -133,10 +142,10 @@ def handle_update_offline(self, file): self.local_update_file_sha = FileUtil.calculate_sha256(file) if os.path.exists(file) is False: self.stdio.error('{0} does not exist.'.format(file)) - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="{0} does not exist.".format(file)) if not file.endswith('.tar'): self.stdio.error('{0} is not a tar file.'.format(file)) - return + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="{0} is not a tar file.".format(file)) ## check_old_files if os.path.exists(os.path.expanduser("~/.obdiag/check.d")): shutil.rmtree(os.path.expanduser("~/.obdiag/check.d")) @@ -147,7 +156,6 @@ def handle_update_offline(self, file): shutil.rmtree(os.path.expanduser("~/.obdiag/gather.d")) if os.path.exists(os.path.expanduser("~/.obdiag/gather")): os.rename(os.path.expanduser("~/.obdiag/gather"), os.path.expanduser("~/.obdiag/gather.d")) - ## rca if os.path.exists(os.path.expanduser("~/.obdiag/rca.d")): shutil.rmtree(os.path.expanduser("~/.obdiag/rca.d")) @@ -159,3 +167,4 @@ def handle_update_offline(self, file): with open(os.path.expanduser("~/.obdiag/data_version.yaml"), 'w') as f: yaml.dump({"data_update_time": int(time.time()), "remote_tar_sha": self.remote_tar_sha}, f) self.stdio.print("[update] Successfully updated. The original data is stored in the *. d folder.") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"msg": "Successfully updated. The original data is stored in the *. d folder."}) From 93a7e4f1976980219f4c2c5c0384d3a5dc2efda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 15:42:09 +0800 Subject: [PATCH 25/35] update --- handler/checker/tasks/observer/cluster/task_opt_stat.yaml | 2 +- init.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/handler/checker/tasks/observer/cluster/task_opt_stat.yaml b/handler/checker/tasks/observer/cluster/task_opt_stat.yaml index 7b1fbcf5..7d926e82 100644 --- a/handler/checker/tasks/observer/cluster/task_opt_stat.yaml +++ b/handler/checker/tasks/observer/cluster/task_opt_stat.yaml @@ -3,7 +3,7 @@ task: - version: "[4.2.0.0,*]" steps: - type: sql - ssh: 'SELECT GROUP_CONCAT(DISTINCT TENANT_ID) + sql: 'SELECT GROUP_CONCAT(DISTINCT TENANT_ID) FROM oceanbase.__all_tenant t WHERE NOT EXISTS(SELECT 1 FROM oceanbase.__all_virtual_task_opt_stat_gather_history h diff --git a/init.sh b/init.sh index 3b9bde96..bb4f6eec 100755 --- a/init.sh +++ b/init.sh @@ -45,3 +45,4 @@ if [ -d "${OBDIAG_HOME}/check_package.yaml" ]; then echo "${OBDIAG_HOME}/*check_package.yaml and ${OBDIAG_HOME}/tasks has been discarded. If you have made any changes to these files on your own, please transfer the relevant data to *check_package.yaml in ${OBDIAG_HOME}/check/" fi echo "Init obdiag finished" +cd - From 79accd8a38c8f8e3fac99054536435b83bc2f289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 15:47:49 +0800 Subject: [PATCH 26/35] update --- result_type.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/result_type.py b/result_type.py index c5755f5a..f77938f8 100644 --- a/result_type.py +++ b/result_type.py @@ -35,12 +35,7 @@ def __init__(self, code, data=None, error_data=None): raise TypeError("ObdiagResult error_data is not str. Please contact the Oceanbase community. ") def set_trace_id(self, trace_id): - if trace_id is None: - raise TypeError("ObdiagResult trace_id is None. Please contact the Oceanbase community. ") - if isinstance(trace_id, str): - self.trace_id = trace_id - else: - raise TypeError("ObdiagResult trace_id is not str. Please contact the Oceanbase community. ") + self.trace_id = "{0}".format(trace_id) def set_command(self, command): self.command = command From f645126ee5d06b4c8ee0526bae42779cd9b0a428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 15:56:44 +0800 Subject: [PATCH 27/35] update --- diag_cmd.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/diag_cmd.py b/diag_cmd.py index 5af3bc2a..9c9f9446 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -272,13 +272,13 @@ def do_command(self): obdiag.set_options(self.opts) obdiag.set_cmds(self.cmds) ret = self._do_command(obdiag) - if isinstance(ret, ObdiagResult) is False: - ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) - ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) - ret.set_trace_id(self.trace_id) - ret.set_command(self.prev_cmd) # if silent is true ,print ret if ROOT_IO.silent: + if isinstance(ret, ObdiagResult) is False: + ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) + ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) + ret.set_trace_id(self.trace_id) + ret.set_command(self.prev_cmd) ROOT_IO.set_silent(False) ROOT_IO.print(ret.get_result()) ROOT_IO.set_silent(True) From dc4f61bea8350db3449273a668b70b1d64aafbf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 20:38:22 +0800 Subject: [PATCH 28/35] update --- core.py | 4 ++-- handler/gather/gather_ash_report.py | 3 ++- handler/gather/gather_awr.py | 4 +++- handler/gather/gather_log.py | 3 ++- handler/gather/gather_obadmin.py | 6 ++++-- handler/gather/gather_obproxy_log.py | 7 ++++--- handler/gather/gather_obstack2.py | 6 ++++-- handler/gather/gather_parameters.py | 5 ++++- handler/gather/gather_perf.py | 6 ++++-- handler/gather/gather_plan_monitor.py | 8 +++++--- handler/gather/gather_scenes.py | 10 ++++++---- handler/gather/gather_sysstat.py | 6 ++++-- handler/gather/gather_tabledump.py | 7 +++++-- handler/gather/gather_variables.py | 5 ++++- handler/gather/scenes/list.py | 11 ++++++++++- 15 files changed, 63 insertions(+), 28 deletions(-) diff --git a/core.py b/core.py index ebb52df9..5532ea5b 100644 --- a/core.py +++ b/core.py @@ -241,7 +241,7 @@ def gather_function(self, function_type, opt): handler_log.handle() handler_obproxy = GatherObProxyLogHandler(self.context) handler_obproxy.handle() - return True + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.context.get_variable("store_dir")}) elif function_type == 'gather_sysstat': handler = GatherOsInfoHandler(self.context) return handler.handle() @@ -262,7 +262,7 @@ def gather_function(self, function_type, opt): return handler.handle() else: self._call_stdio('error', 'Not support gather function: {0}'.format(function_type)) - return False + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data='Not support gather function: {0}'.format(function_type)) def gather_obproxy_log(self, opt): config = self.config_manager diff --git a/handler/gather/gather_ash_report.py b/handler/gather/gather_ash_report.py index 883e58fa..6cd91510 100644 --- a/handler/gather/gather_ash_report.py +++ b/handler/gather/gather_ash_report.py @@ -67,7 +67,7 @@ def handle(self): return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") self.__init_report_path() self.execute() - self.__print_result() + return self.__print_result() def version_check(self): observer_version = "" @@ -190,3 +190,4 @@ def init_option(self): def __print_result(self): self.stdio.print(Fore.YELLOW + "\nGather ash_report results stored in this directory: {0}".format(self.report_path) + Style.RESET_ALL) self.stdio.print("") + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.report_path}) diff --git a/handler/gather/gather_awr.py b/handler/gather/gather_awr.py index bec5b9e6..ae6b60f5 100644 --- a/handler/gather/gather_awr.py +++ b/handler/gather/gather_awr.py @@ -27,6 +27,7 @@ from common.tool import Util from common.tool import TimeUtils from common.ocp import ocp_task, ocp_api +from result_type import ObdiagResult class GatherAwrHandler(object): @@ -100,7 +101,8 @@ def handle_awr_from_ocp(ocp_url, cluster_name): # 将汇总结果持久化记录到文件中 FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) - return gather_tuples, gather_pack_path_dict + # return gather_tuples, gather_pack_path_dict + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __download_report(self, store_path, name, report_id): """ diff --git a/handler/gather/gather_log.py b/handler/gather/gather_log.py index 80f6cb81..5246ed16 100644 --- a/handler/gather/gather_log.py +++ b/handler/gather/gather_log.py @@ -29,6 +29,7 @@ from common.tool import DirectoryUtil from common.tool import FileUtil from common.tool import NetUtils +from result_type import ObdiagResult class GatherLogHandler(BaseShellHandler): @@ -168,7 +169,7 @@ def handle_from_node(node): # Persist the summary results to a file FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) last_info = "For result details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(pack_dir_this_command, "result_summary.txt")) - return True + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, pack_dir_this_command, node): resp = {"skip": False, "error": "", "zip_password": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_obadmin.py b/handler/gather/gather_obadmin.py index a7c3da04..93c6ece2 100644 --- a/handler/gather/gather_obadmin.py +++ b/handler/gather/gather_obadmin.py @@ -31,6 +31,7 @@ from common.tool import DirectoryUtil from common.tool import FileUtil from common.tool import NetUtils +from result_type import ObdiagResult class GatherObAdminHandler(BaseShellHandler): @@ -116,10 +117,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") pack_dir_this_command = os.path.join(self.local_stored_path, "obdiag_gather_pack_{0}".format(TimeUtils.timestamp_to_filename_time(self.gather_timestamp))) self.stdio.verbose("Use {0} as pack dir.".format(pack_dir_this_command)) gather_tuples = [] @@ -152,6 +153,7 @@ def handle_from_node(node): FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) last_info = "For result details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(pack_dir_this_command, "result_summary.txt")) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, local_stored_path, node): resp = {"skip": False, "error": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_obproxy_log.py b/handler/gather/gather_obproxy_log.py index ee32c8b7..1550505d 100644 --- a/handler/gather/gather_obproxy_log.py +++ b/handler/gather/gather_obproxy_log.py @@ -31,6 +31,7 @@ from common.tool import FileUtil from common.tool import NetUtils from common.tool import TimeUtils +from result_type import ObdiagResult class GatherObProxyLogHandler(BaseShellHandler): @@ -136,10 +137,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") if self.is_scene: pack_dir_this_command = self.gather_pack_dir else: @@ -171,7 +172,7 @@ def handle_from_node(node): self.pack_dir_this_command = pack_dir_this_command FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) last_info = "For result details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(pack_dir_this_command, "result_summary.txt")) - return True + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, node, pack_dir_this_command): resp = {"skip": False, "error": "", "zip_password": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_obstack2.py b/handler/gather/gather_obstack2.py index 9b0e8084..4a922f6b 100644 --- a/handler/gather/gather_obstack2.py +++ b/handler/gather/gather_obstack2.py @@ -32,6 +32,7 @@ from common.tool import FileUtil from common.tool import NetUtils from common.tool import StringUtils +from result_type import ObdiagResult class GatherObstack2Handler(BaseShellHandler): @@ -77,10 +78,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") if self.is_scene: pack_dir_this_command = self.local_stored_path else: @@ -104,6 +105,7 @@ def handle_from_node(node): # Persist the summary results to a file FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) last_info = "For result details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(pack_dir_this_command, "result_summary.txt")) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, local_stored_path, node): resp = {"skip": False, "error": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_parameters.py b/handler/gather/gather_parameters.py index 187fb779..359ff423 100644 --- a/handler/gather/gather_parameters.py +++ b/handler/gather/gather_parameters.py @@ -23,6 +23,8 @@ import csv from colorama import Fore, Style +from result_type import ObdiagResult + class GatherParametersHandler(object): def __init__(self, context, gather_pack_dir='./'): @@ -53,13 +55,14 @@ def __init__(self, context, gather_pack_dir='./'): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") # example of the format of pack dir for this command: (gather_pack_dir)/gather_pack_20190610123344 pack_dir_this_command = os.path.join(self.gather_pack_dir, "gather_parameters") self.stdio.verbose("Use {0} as pack dir.".format(pack_dir_this_command)) DirectoryUtil.mkdir(path=pack_dir_this_command, stdio=self.stdio) self.gather_pack_dir = pack_dir_this_command self.execute() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"gather_pack_dir": pack_dir_this_command}) def init_option(self): options = self.context.options diff --git a/handler/gather/gather_perf.py b/handler/gather/gather_perf.py index db792d3d..61d71450 100644 --- a/handler/gather/gather_perf.py +++ b/handler/gather/gather_perf.py @@ -30,6 +30,7 @@ from common.tool import FileUtil from common.tool import NetUtils from common.tool import TimeUtils +from result_type import ObdiagResult class GatherPerfHandler(BaseShellHandler): @@ -79,10 +80,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") if self.is_scene: pack_dir_this_command = self.local_stored_path else: @@ -113,6 +114,7 @@ def handle_from_node(node): # Persist the summary results to a file FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) last_info = "For result details, please run cmd \033[32m' cat {0} '\033[0m\n".format(os.path.join(pack_dir_this_command, "result_summary.txt")) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, node, local_stored_path): resp = {"skip": False, "error": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_plan_monitor.py b/handler/gather/gather_plan_monitor.py index 6d248bcf..7ab0ba73 100644 --- a/handler/gather/gather_plan_monitor.py +++ b/handler/gather/gather_plan_monitor.py @@ -33,6 +33,7 @@ from common.tool import FileUtil from common.tool import TimeUtils from handler.gather.gather_tabledump import GatherTableDumpHandler +from result_type import ObdiagResult class GatherPlanMonitorHandler(object): @@ -95,10 +96,10 @@ def __init_db_connector(self): def handle(self): if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if self.is_scene: pack_dir_this_command = self.local_stored_path else: @@ -219,7 +220,8 @@ def handle_plan_monitor_from_ob(cluster_name): self.stdio.print(summary_tuples) # 将汇总结果持久化记录到文件中 FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) - return gather_tuples, gather_pack_path_dict + # return gather_tuples, gather_pack_path_dict + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __init_db_conn(self, env): try: diff --git a/handler/gather/gather_scenes.py b/handler/gather/gather_scenes.py index d54e2f57..561f4fe1 100644 --- a/handler/gather/gather_scenes.py +++ b/handler/gather/gather_scenes.py @@ -18,6 +18,7 @@ import os import re +from result_type import ObdiagResult from stdio import SafeStdio import datetime from handler.gather.scenes.base import SceneBase @@ -65,19 +66,19 @@ def init_config(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init config failed") self.__init_variables() self.__init_report_path() self.__init_task_names() self.execute() if self.is_inner: result = self.__get_sql_result() - return result + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": result}) else: - self.__print_result() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": result}) def execute(self): try: @@ -231,3 +232,4 @@ def __get_sql_result(self): def __print_result(self): self.stdio.print(Fore.YELLOW + "\nGather scene results stored in this directory: {0}\n".format(self.report_path) + Style.RESET_ALL) + return self.report_path diff --git a/handler/gather/gather_sysstat.py b/handler/gather/gather_sysstat.py index a77dff57..f6aea7c2 100644 --- a/handler/gather/gather_sysstat.py +++ b/handler/gather/gather_sysstat.py @@ -29,6 +29,7 @@ from common.tool import FileUtil from common.tool import NetUtils from common.tool import TimeUtils +from result_type import ObdiagResult class GatherOsInfoHandler(BaseShellHandler): @@ -80,10 +81,10 @@ def init_option(self): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, "init option failed") if not self.init_config(): self.stdio.error('init config failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, "init config failed") if self.is_scene: pack_dir_this_command = self.local_stored_path @@ -114,6 +115,7 @@ def handle_from_node(node): self.stdio.print(summary_tuples) # Persist the summary results to a file FileUtil.write_append(os.path.join(pack_dir_this_command, "result_summary.txt"), summary_tuples) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def __handle_from_node(self, node, local_stored_path): resp = {"skip": False, "error": "", "gather_pack_path": ""} diff --git a/handler/gather/gather_tabledump.py b/handler/gather/gather_tabledump.py index afecfd24..45cffccf 100644 --- a/handler/gather/gather_tabledump.py +++ b/handler/gather/gather_tabledump.py @@ -18,6 +18,8 @@ import os import time + +from result_type import ObdiagResult from stdio import SafeStdio from common.ob_connector import OBConnector from common.tool import StringUtils @@ -99,10 +101,10 @@ def handle(self): self.start_time = time.time() if not self.init(): self.stdio.error('init failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init failed") excute_status = self.execute() if not self.is_innner and excute_status: - self.__print_result() + return self.__print_result() def execute(self): try: @@ -253,3 +255,4 @@ def __print_result(self): self.stdio.print("\nAnalyze SQL Summary:") self.stdio.print(table) self.stdio.print("\n") + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, data={"firstrow": data}) diff --git a/handler/gather/gather_variables.py b/handler/gather/gather_variables.py index 6c49b538..970e5ad2 100644 --- a/handler/gather/gather_variables.py +++ b/handler/gather/gather_variables.py @@ -22,6 +22,8 @@ import csv from colorama import Fore, Style +from result_type import ObdiagResult + class GatherVariablesHandler(object): def __init__(self, context, gather_pack_dir='./'): @@ -52,12 +54,13 @@ def __init__(self, context, gather_pack_dir='./'): def handle(self): if not self.init_option(): self.stdio.error('init option failed') - return False + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init option failed") pack_dir_this_command = os.path.join(self.gather_pack_dir, "gather_variables") self.stdio.verbose("Use {0} as pack dir.".format(pack_dir_this_command)) DirectoryUtil.mkdir(path=pack_dir_this_command, stdio=self.stdio) self.gather_pack_dir = pack_dir_this_command self.execute() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": pack_dir_this_command}) def init_option(self): options = self.context.options diff --git a/handler/gather/scenes/list.py b/handler/gather/scenes/list.py index 0af2d06b..099e13a8 100644 --- a/handler/gather/scenes/list.py +++ b/handler/gather/scenes/list.py @@ -17,6 +17,8 @@ """ import os + +from result_type import ObdiagResult from stdio import SafeStdio from common.tool import YamlUtils from handler.gather.scenes.register import hardcode_scene_list @@ -44,8 +46,9 @@ def handle(self): self.stdio.verbose("len of observer_tasks: {0}; len of observer_tasks: {1}; len of observer_tasks: {2};".format(len(self.observer_tasks), len(self.obproxy_tasks), len(self.other_tasks))) if (len(self.observer_tasks) + len(self.obproxy_tasks) + len(self.other_tasks)) == 0: self.stdio.error("Failed to find any tasks") + return ObdiagResult(ObdiagResult.INPUT_ERROR_CODE, error_data="Failed to find any tasks") else: - self.print_scene_data() + return self.print_scene_data() def get_all_yaml_tasks(self): try: @@ -116,18 +119,24 @@ def print_scene_data(self): sorted_observer_tasks_dict = {} sorted_obproxy_tasks_dict = {} sorted_other_tasks_dict = {} + result_data = {} if self.other_tasks: sorted_other_tasks = sorted(self.other_tasks.items(), key=lambda x: x[0]) sorted_other_tasks_dict = {k: v for k, v in sorted_other_tasks} Util.print_title("Other Problem Gather Scenes", stdio=self.stdio) Util.print_scene(sorted_other_tasks_dict, stdio=self.stdio) + result_data["sorted_other_tasks"] = sorted_other_tasks_dict if self.obproxy_tasks: sorted_obproxy_tasks = sorted(self.obproxy_tasks.items(), key=lambda x: x[0]) sorted_obproxy_tasks_dict = {k: v for k, v in sorted_obproxy_tasks} Util.print_title("Obproxy Problem Gather Scenes", stdio=self.stdio) Util.print_scene(sorted_obproxy_tasks_dict, stdio=self.stdio) + result_data["sorted_obproxy_tasks"] = sorted_obproxy_tasks_dict + if self.observer_tasks: sorted_observer_tasks = sorted(self.observer_tasks.items(), key=lambda x: x[0]) sorted_observer_tasks_dict = {k: v for k, v in sorted_observer_tasks} Util.print_title("Observer Problem Gather Scenes", stdio=self.stdio) Util.print_scene(sorted_observer_tasks_dict, stdio=self.stdio) + result_data["sorted_observer_tasks"] = sorted_observer_tasks_dict + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data=result_data) From 9b7f1eb373aed0c0f96562c98ddfc6c98c148a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Wed, 14 Aug 2024 20:39:58 +0800 Subject: [PATCH 29/35] update --- diag_cmd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/diag_cmd.py b/diag_cmd.py index 9c9f9446..4fa4fcfa 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -276,7 +276,7 @@ def do_command(self): if ROOT_IO.silent: if isinstance(ret, ObdiagResult) is False: ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) - ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Please contact thebase community."}) + ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Maybe the command not support silent. Please contact thebase community."}) ret.set_trace_id(self.trace_id) ret.set_command(self.prev_cmd) ROOT_IO.set_silent(False) From 40d6cd2a87f524ce459ef65ff2f5168a685ec6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Thu, 15 Aug 2024 14:59:00 +0800 Subject: [PATCH 30/35] update --- core.py | 9 ++++++--- diag_cmd.py | 3 +++ handler/checker/check_handler.py | 2 +- handler/checker/check_list.py | 18 +++++++++++------- result_type.py | 14 +++++++------- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/core.py b/core.py index 5532ea5b..c8439023 100644 --- a/core.py +++ b/core.py @@ -333,14 +333,17 @@ def check(self, opts): self.set_context('check', 'check', config) obproxy_check_handler = None observer_check_handler = None + result_data = {} if self.context.obproxy_config.get("servers") is not None and len(self.context.obproxy_config.get("servers")) > 0: obproxy_check_handler = CheckHandler(self.context, check_target_type="obproxy") obproxy_check_handler.handle() - obproxy_check_handler.execute() + obproxy_result = obproxy_check_handler.execute() + result_data['obproxy'] = obproxy_result if self.context.cluster_config.get("servers") is not None and len(self.context.cluster_config.get("servers")) > 0: observer_check_handler = CheckHandler(self.context, check_target_type="observer") observer_check_handler.handle() - observer_check_handler.execute() + observer_result = observer_check_handler.execute() + result_data['observer'] = observer_result if obproxy_check_handler is not None: obproxy_report_path = os.path.expanduser(obproxy_check_handler.report.get_report_path()) if os.path.exists(obproxy_report_path): @@ -349,7 +352,7 @@ def check(self, opts): observer_report_path = os.path.expanduser(observer_check_handler.report.get_report_path()) if os.path.exists(observer_report_path): self.stdio.print("Check observer finished. For more details, please run cmd'" + Fore.YELLOW + " cat {0} ".format(observer_check_handler.report.get_report_path()) + Style.RESET_ALL + "'") - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={}) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data=result_data) def check_list(self, opts): config = self.config_manager diff --git a/diag_cmd.py b/diag_cmd.py index 4fa4fcfa..b0a2a72b 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -272,6 +272,7 @@ def do_command(self): obdiag.set_options(self.opts) obdiag.set_cmds(self.cmds) ret = self._do_command(obdiag) + exit_code = 0 # if silent is true ,print ret if ROOT_IO.silent: if isinstance(ret, ObdiagResult) is False: @@ -286,6 +287,8 @@ def do_command(self): ROOT_IO.print('Trace ID: %s' % self.trace_id) ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, self.trace_id)) telemetry.put_data() + if ret.get_code() == ObdiagResult.SUCCESS_CODE: + return True except NotImplementedError: ROOT_IO.exception('command \'%s\' is not implemented' % self.prev_cmd) except SystemExit: diff --git a/handler/checker/check_handler.py b/handler/checker/check_handler.py index 340d77c6..1e899562 100644 --- a/handler/checker/check_handler.py +++ b/handler/checker/check_handler.py @@ -241,7 +241,7 @@ def execute(self): t_report = self.execute_one(task) self.report.add_task_report(t_report) self.report.export_report() - return self.report + return self.report.report_tobeMap() except CheckrReportException as e: self.stdio.error("Report error :{0}".format(e)) self.stdio.verbose(traceback.format_exc()) diff --git a/handler/checker/check_list.py b/handler/checker/check_list.py index 3a5c5d9d..8a5d6451 100644 --- a/handler/checker/check_list.py +++ b/handler/checker/check_list.py @@ -34,7 +34,7 @@ def handle(self): self.stdio.verbose("list check cases") entries = os.listdir(self.work_path) files = [f for f in entries if os.path.isfile(os.path.join(self.work_path, f))] - result_map = {"data": {}} + result_map = {} for file in files: if "check_package" in file: cases_map = {"all": {"name": "all", "command": "obdiag check", "info_en": "default check all task without filter", "info_cn": "默认执行除filter组里的所有巡检项"}} @@ -50,6 +50,8 @@ def handle(self): # read yaml file with open(file, 'r') as f: package_file_data = yaml.safe_load(f) + result_map[target] = {} + result_map[target]["commands"] = [] if not package_file_data or len(package_file_data) == 0: self.stdio.warn("No data check package data :{0} ".format(file)) continue @@ -68,12 +70,14 @@ def handle(self): "info_en": package_file_data[package_data].get("info_en") or "", "info_cn": package_file_data[package_data].get("info_cn") or "", } - result_map["data"]["commands"] = { - "name": package_data, - "command": "obdiag check --{0}={1}".format(package_target, package_data), - "info_en": package_file_data[package_data].get("info_en") or "", - "info_cn": package_file_data[package_data].get("info_cn") or "", - } + result_map[target]["commands"].append( + { + "name": package_data, + "command": "obdiag check --{0}={1}".format(package_target, package_data), + "info_en": package_file_data[package_data].get("info_en") or "", + "info_cn": package_file_data[package_data].get("info_cn") or "", + } + ) Util.print_title("check cases about {0}".format(target), stdio=self.stdio) Util.print_scene(cases_map, stdio=self.stdio) return ObdiagResult(ObdiagResult.SUCCESS_CODE, data=result_map) diff --git a/result_type.py b/result_type.py index f77938f8..71f30b01 100644 --- a/result_type.py +++ b/result_type.py @@ -19,13 +19,10 @@ def __init__(self, code, data=None, error_data=None): self.error_data = error_data if code is None: raise TypeError("ObdiagResult code is None. Please contact the Oceanbase community. ") - if isinstance(code, int): - self.code = str(code) - else: - raise TypeError("ObdiagResult code is not int. Please contact the Oceanbase community. ") + self.code = code if data is not None: if isinstance(data, dict): - self.result = data + self.data = data else: raise TypeError("ObdiagResult data is not dict. Please contact the Oceanbase community. ") if error_data is not None: @@ -41,5 +38,8 @@ def set_command(self, command): self.command = command def get_result(self): - result = {"code": self.code, "data": self.result, "error_data": self.error_data, "trace_id": self.trace_id, "command": self.command} - return json.dumps(result) + result = {"code": self.code, "data": self.data, "error_data": self.error_data, "trace_id": self.trace_id, "command": self.command} + return json.dumps(result, ensure_ascii=False) + + def get_code(self): + return self.code From 53dfb463fc71f2ccc723fdb80f7b6bcfab853924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Fri, 16 Aug 2024 18:20:16 +0800 Subject: [PATCH 31/35] update --- core.py | 3 +-- diag_cmd.py | 11 +++++++++-- handler/gather/gather_scenes.py | 4 ++-- handler/gather/gather_tabledump.py | 6 ++++-- update/update.py | 16 ++++++++-------- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/core.py b/core.py index c8439023..95cb1206 100644 --- a/core.py +++ b/core.py @@ -240,8 +240,7 @@ def gather_function(self, function_type, opt): handler_log = GatherLogHandler(self.context) handler_log.handle() handler_obproxy = GatherObProxyLogHandler(self.context) - handler_obproxy.handle() - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.context.get_variable("store_dir")}) + return handler_obproxy.handle() elif function_type == 'gather_sysstat': handler = GatherOsInfoHandler(self.context) return handler.handle() diff --git a/diag_cmd.py b/diag_cmd.py index b0a2a72b..d934ed11 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -277,9 +277,16 @@ def do_command(self): if ROOT_IO.silent: if isinstance(ret, ObdiagResult) is False: ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) - ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data={"err_info": "The return value of the command is not ObdiagResult. Maybe the command not support silent. Please contact thebase community."}) + ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data= "The return value of the command is not ObdiagResult. Maybe the command not support silent. Please contact thebase community." ) ret.set_trace_id(self.trace_id) - ret.set_command(self.prev_cmd) + + def args_to_str(args): + args_str = "" + for arg in args: + args_str += arg + " " + return args_str.strip() + + ret.set_command(self.prev_cmd + " " + args_to_str(self.args)) ROOT_IO.set_silent(False) ROOT_IO.print(ret.get_result()) ROOT_IO.set_silent(True) diff --git a/handler/gather/gather_scenes.py b/handler/gather/gather_scenes.py index 561f4fe1..55a17d91 100644 --- a/handler/gather/gather_scenes.py +++ b/handler/gather/gather_scenes.py @@ -76,9 +76,9 @@ def handle(self): self.execute() if self.is_inner: result = self.__get_sql_result() - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": result}) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.report_path}) else: - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": result}) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.report_path}) def execute(self): try: diff --git a/handler/gather/gather_tabledump.py b/handler/gather/gather_tabledump.py index 45cffccf..88ac6078 100644 --- a/handler/gather/gather_tabledump.py +++ b/handler/gather/gather_tabledump.py @@ -104,7 +104,9 @@ def handle(self): return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="init failed") excute_status = self.execute() if not self.is_innner and excute_status: - return self.__print_result() + self.__print_result() + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.store_dir}) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="execute failed") def execute(self): try: @@ -255,4 +257,4 @@ def __print_result(self): self.stdio.print("\nAnalyze SQL Summary:") self.stdio.print(table) self.stdio.print("\n") - return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, data={"firstrow": data}) + return diff --git a/update/update.py b/update/update.py index a59b1117..acbab830 100644 --- a/update/update.py +++ b/update/update.py @@ -60,13 +60,13 @@ def execute(self): return self.handle_update_offline(file_path) if NetUtils.network_connectivity(remote_server) is False: self.stdio.warn("[update] network connectivity failed. Please check your network connection.") - return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "network connectivity failed. Please check your network connection."}) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="network connectivity failed. Please check your network connection.") NetUtils.download_file(remote_version_file_name, os.path.expanduser(local_version_file_name)) with open(local_version_file_name, 'r') as file: remote_data = yaml.safe_load(file) if remote_data.get("obdiag_version") is None: self.stdio.warn("obdiag_version is None. Do not perform the upgrade process.") - return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "obdiag_version is None. Do not perform the upgrade process."}) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="obdiag_version is None. Do not perform the upgrade process.") else: self.remote_obdiag_version = remote_data["obdiag_version"].strip() if StringUtils.compare_versions_greater(self.remote_obdiag_version, self.local_obdiag_version): @@ -77,15 +77,15 @@ def execute(self): ) return ObdiagResult( ObdiagResult.SERVER_ERROR_CODE, - error_data={ - "msg": "remote_obdiag_version is {0}. local_obdiag_version is {1}. " - "remote_obdiag_version>local_obdiag_version. Unable to update dependency files, please upgrade " - "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version) - }, + error_data= + "remote_obdiag_version is {0}. local_obdiag_version is {1}. " + "remote_obdiag_version>local_obdiag_version. Unable to update dependency files, please upgrade " + "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version) + , ) if remote_data.get("remote_tar_sha") is None: self.stdio.warn("remote_tar_sha is None. Do not perform the upgrade process.") - return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data={"msg": "remote_tar_sha is None. Do not perform the upgrade process."}) + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data= "remote_tar_sha is None. Do not perform the upgrade process.") else: self.remote_tar_sha = remote_data["remote_tar_sha"] # need update? From 8f6876fe49debbc55d4a811e8296a73b72ae268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 19 Aug 2024 17:16:58 +0800 Subject: [PATCH 32/35] fix some bug --- diag_cmd.py | 2 +- handler/analyzer/analyze_flt_trace.py | 7 ++++++- handler/analyzer/analyze_parameter.py | 2 +- handler/rca/rca_handler.py | 2 +- stdio.py | 4 ++++ update/update.py | 8 +++----- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/diag_cmd.py b/diag_cmd.py index d934ed11..dc9064a6 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -277,7 +277,7 @@ def do_command(self): if ROOT_IO.silent: if isinstance(ret, ObdiagResult) is False: ROOT_IO.error('The return value of the command is not ObdiagResult. Please contact thebase community. The return value is: {0}'.format(ret)) - ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data= "The return value of the command is not ObdiagResult. Maybe the command not support silent. Please contact thebase community." ) + ret = ObdiagResult(code=ObdiagResult.SERVER_ERROR_CODE, error_data="The return value of the command is not ObdiagResult. Maybe the command not support silent. Please contact thebase community.") ret.set_trace_id(self.trace_id) def args_to_str(args): diff --git a/handler/analyzer/analyze_flt_trace.py b/handler/analyzer/analyze_flt_trace.py index 8d9dff6b..8aa0cacf 100644 --- a/handler/analyzer/analyze_flt_trace.py +++ b/handler/analyzer/analyze_flt_trace.py @@ -120,7 +120,8 @@ def handle_from_node(node): data = future.result() tree.build(data) # output tree - return self.__output(local_store_parent_dir, tree, self.output) + result = self.__output(local_store_parent_dir, tree, self.output) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": local_store_parent_dir, "result": result}) def __handle_from_node(self, node, old_files, local_store_parent_dir): resp = {"skip": False, "error": ""} @@ -348,8 +349,12 @@ def __output(self, result_dir, tree, output_terminal=60): self.stdio.print(last_info) result_info = "" with open(filename, 'r', encoding='utf-8') as f: + line_nu = 0 for line in f: result_info += line + line_nu += 1 + if line_nu > 60: + break return result_info def parse_file(self, file): diff --git a/handler/analyzer/analyze_parameter.py b/handler/analyzer/analyze_parameter.py index f4db52a8..40e5c012 100644 --- a/handler/analyzer/analyze_parameter.py +++ b/handler/analyzer/analyze_parameter.py @@ -287,7 +287,7 @@ def alalyze_parameter_diff(self): fp.close() if not is_empty: self.stdio.print("Analyze parameter diff finished. For more details, please run cmd '" + Fore.YELLOW + " cat {0} ".format(file_name) + Style.RESET_ALL + "'") - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": report_diff_tbs, "file_name": file_name}) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": report_diff_tbs, "store_dir": file_name}) else: self.stdio.print("Analyze parameter diff finished. All parameter settings are consistent among observers") return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"result": "Analyze parameter diff finished. All parameter settings are consistent among observers"}) diff --git a/handler/rca/rca_handler.py b/handler/rca/rca_handler.py index d72715eb..1fe3a14e 100644 --- a/handler/rca/rca_handler.py +++ b/handler/rca/rca_handler.py @@ -183,7 +183,7 @@ def execute(self): except Exception as e: raise Exception("rca_scene.export_result err: {0}".format(e)) self.stdio.print("rca finished. For more details, the result on '" + Fore.YELLOW + self.get_result_path() + Style.RESET_ALL + "' \nYou can get the suggest by '" + Fore.YELLOW + "cat " + self.get_result_path() + "/record" + Style.RESET_ALL + "'") - return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.get_result_path(), "record": self.rca_scene.records_data()}) + return ObdiagResult(ObdiagResult.SUCCESS_CODE, data={"store_dir": self.get_result_path(), "record": self.rca_scene.Result.records_data()}) class RcaScene: diff --git a/stdio.py b/stdio.py index dc09820d..4d2962a4 100644 --- a/stdio.py +++ b/stdio.py @@ -638,6 +638,8 @@ def _stop_sync_obj(self, sync_clz, stop_type, *arg, **kwargs): return ret def start_loading(self, text, *arg, **kwargs): + if self.silent: + return True if self.sync_obj: return False self.sync_obj = self._start_sync_obj(IOHalo, lambda x: x.stop_loading('fail'), *arg, **kwargs) @@ -646,6 +648,8 @@ def start_loading(self, text, *arg, **kwargs): return self.sync_obj.start(text) def stop_loading(self, stop_type, *arg, **kwargs): + if self.silent: + return True if not isinstance(self.sync_obj, IOHalo): return False if getattr(self.sync_obj, stop_type, False): diff --git a/update/update.py b/update/update.py index acbab830..c9b73ae6 100644 --- a/update/update.py +++ b/update/update.py @@ -77,15 +77,13 @@ def execute(self): ) return ObdiagResult( ObdiagResult.SERVER_ERROR_CODE, - error_data= - "remote_obdiag_version is {0}. local_obdiag_version is {1}. " + error_data="remote_obdiag_version is {0}. local_obdiag_version is {1}. " "remote_obdiag_version>local_obdiag_version. Unable to update dependency files, please upgrade " - "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version) - , + "obdiag. Do not perform the upgrade process.".format(self.remote_obdiag_version, self.local_obdiag_version), ) if remote_data.get("remote_tar_sha") is None: self.stdio.warn("remote_tar_sha is None. Do not perform the upgrade process.") - return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data= "remote_tar_sha is None. Do not perform the upgrade process.") + return ObdiagResult(ObdiagResult.SERVER_ERROR_CODE, error_data="remote_tar_sha is None. Do not perform the upgrade process.") else: self.remote_tar_sha = remote_data["remote_tar_sha"] # need update? From 667ed182a5a228410fc2f438401bfa84105286af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Mon, 19 Aug 2024 17:39:53 +0800 Subject: [PATCH 33/35] delete build tag --- .github/workflows/build_package.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build_package.yml b/.github/workflows/build_package.yml index 4aacc390..6287fa6e 100644 --- a/.github/workflows/build_package.yml +++ b/.github/workflows/build_package.yml @@ -7,7 +7,6 @@ on: push: branches: - master - - 2.4.0-silent-print env: ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true From ef80ab36c008fa7029a6a3549c339efebd7fdb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 20 Aug 2024 14:18:35 +0800 Subject: [PATCH 34/35] delete silent note --- stdio.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stdio.py b/stdio.py index 4d2962a4..5a192ea9 100644 --- a/stdio.py +++ b/stdio.py @@ -366,7 +366,6 @@ class IO(object): VERBOSE_LEVEL = 0 WARNING_PREV = FormtatText.warning('[WARN]') ERROR_PREV = FormtatText.error('[ERROR]') - # The silent flag is used as a marker to indicate whether the msg is printed on the stream. If it is true, it will not be output to the steam def __init__(self, level, msg_lv=MsgLevel.DEBUG, use_cache=False, track_limit=0, root_io=None, input_stream=SysStdin, output_stream=sys.stdout, error_stream=sys.stdout, silent=False): self.silent = silent From 4521c72ce4b4787f44d6d079d740b82aa22f6273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=A0=E7=A3=8A?= Date: Tue, 20 Aug 2024 17:22:51 +0800 Subject: [PATCH 35/35] code fix --- diag_cmd.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/diag_cmd.py b/diag_cmd.py index dc9064a6..95d5dc14 100644 --- a/diag_cmd.py +++ b/diag_cmd.py @@ -294,8 +294,12 @@ def args_to_str(args): ROOT_IO.print('Trace ID: %s' % self.trace_id) ROOT_IO.print('If you want to view detailed obdiag logs, please run: {0} display-trace {1}'.format(obdiag_bin, self.trace_id)) telemetry.put_data() - if ret.get_code() == ObdiagResult.SUCCESS_CODE: - return True + if ROOT_IO.silent: + if ret.get_code() == ObdiagResult.SUCCESS_CODE: + return True + else: + return False + return True except NotImplementedError: ROOT_IO.exception('command \'%s\' is not implemented' % self.prev_cmd) except SystemExit: