From 987fbaa6c1975ee92ce7b201d2114640d7bc1a36 Mon Sep 17 00:00:00 2001 From: xin liang Date: Mon, 20 May 2024 22:07:27 +0800 Subject: [PATCH 1/2] Dev: Parsing resource meta attributes dynamically (jsc#PED-8261, jsc#PED-8249) With the latest pacemaker version (since 2.1.8), crmsh can get the resource meta attributes by parsing the output of `crm_resource --list-options=primitive --output-as=xml` command. The benefit of this approach: - Avoid hardcoding the resource meta attributes - Provide help info at interactive mode for each meta attribute --- crmsh/cibconfig.py | 8 ++++---- crmsh/ra.py | 17 +++++++++++++++++ crmsh/ui_configure.py | 16 ++++++++++++++-- crmsh/utils.py | 9 +++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/crmsh/cibconfig.py b/crmsh/cibconfig.py index 93579d8580..da59d465ed 100644 --- a/crmsh/cibconfig.py +++ b/crmsh/cibconfig.py @@ -25,7 +25,7 @@ from . import crm_gv from . import ui_utils from . import userdir -from .ra import get_ra, get_properties_list, get_pe_meta, get_properties_meta, RAInfo +from .ra import get_ra, get_properties_list, get_pe_meta, get_properties_meta, RAInfo, get_resource_meta_list from .utils import ext_cmd, safe_open_w, pipe_string, safe_close_w, crm_msec from .utils import ask, lines2cli, olist from .utils import page_string, str2tmp, ensure_sudo_readable @@ -1571,7 +1571,7 @@ def check_sanity(self): if self.node is None: # eh? logger.error("%s: no xml (strange)", self.obj_id) return utils.get_check_rc() - rc3 = sanity_check_meta(self.obj_id, self.node, constants.rsc_meta_attributes) + rc3 = sanity_check_meta(self.obj_id, self.node, get_resource_meta_list()) if self.obj_type == "primitive": r_node = reduce_primitive(self.node) if r_node is None: @@ -1681,7 +1681,7 @@ def check_sanity(self): if self.node is None: # eh? logger.error("%s: no xml (strange)", self.obj_id) return utils.get_check_rc() - l = constants.rsc_meta_attributes + l = get_resource_meta_list() if self.obj_type == "clone": l += constants.clone_meta_attributes elif self.obj_type == "ms": @@ -2045,7 +2045,7 @@ def check_sanity(self): elif self.obj_type == "op_defaults": l = schema.get('attr', 'op', 'a') elif self.obj_type == "rsc_defaults": - l = constants.rsc_meta_attributes + l = get_resource_meta_list() rc = sanity_check_nvpairs(self.obj_id, self.node, l) return rc diff --git a/crmsh/ra.py b/crmsh/ra.py index f6814cafcc..316c0df58e 100644 --- a/crmsh/ra.py +++ b/crmsh/ra.py @@ -228,6 +228,23 @@ def get_properties_list(): return [] +@utils.memoize +def get_resource_meta(): + resource_meta = utils.get_resource_metadata() + if resource_meta: + return RAInfo("resource_meta", None, meta_string=resource_meta) + return None + + +@utils.memoize +def get_resource_meta_list(): + try: + return list(get_resource_meta().params().keys()) + # use legacy code to get the resource metadata list + except: + return constants.rsc_meta_attributes + + def prog_meta(prog): ''' Do external program metadata. diff --git a/crmsh/ui_configure.py b/crmsh/ui_configure.py index 7915eb23c3..1b4aed7546 100644 --- a/crmsh/ui_configure.py +++ b/crmsh/ui_configure.py @@ -238,9 +238,14 @@ def _prim_meta_completer(agent, args): completing = args[-1] if completing == 'meta': return ['meta'] + if completing.endswith('='): + if len(completing) > 1 and options.interactive: + topic = completing[:-1] + CompletionHelp.help(topic, agent.meta_parameter(topic), args) + return [] if '=' in completing: return [] - return utils.filter_keys(constants.rsc_meta_attributes, args) + return utils.filter_keys(ra.get_resource_meta_list(), args) def _prim_op_completer(agent, args): @@ -304,6 +309,11 @@ def _property_completer(args): return _prim_params_completer(agent, args) +def _rsc_meta_completer(args): + agent = ra.get_resource_meta() + return _prim_meta_completer(agent, args) + + def primitive_complete_complex(args): ''' This completer depends on the content of the line, i.e. on @@ -334,6 +344,8 @@ def primitive_complete_complex(args): if last_keyw is None: return [] + if last_keyw == 'meta': + agent = ra.get_resource_meta() complete_results = completers_set[last_keyw](agent, args) if len(args) > 4 and '=' in args[-1]: return complete_results + keywords @@ -1125,7 +1137,7 @@ def do_property(self, context, *args): return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') - @command.completers_repeating(_prim_meta_completer) + @command.completers_repeating(_rsc_meta_completer) def do_rsc_defaults(self, context, *args): "usage: rsc_defaults [$id=]