def remove_levels_by_params( topology_el: _Element, level=None, # TODO create a special type, so that it cannot accept any string target_type: Optional[str] = None, target_value=None, devices: Optional[Iterable[str]] = None, # TODO remove, deprecated backward compatibility layer ignore_if_missing: bool = False, # TODO remove, deprecated backward compatibility layer validate_device_ids: bool = True, ) -> ReportItemList: """ Remove specified fencing level(s) topology_el -- etree element to remove the levels from int|string level -- level (index) of the fencing level to remove target_type -- the removed fencing level target value type mixed target_value -- the removed fencing level target value devices -- list of stonith devices of the removed fencing level ignore_if_missing -- when True, do not report if level not found """ # Do not ever remove a fencing-topology element, even if it is empty. There # may be ACLs set in pacemaker which allow "write" for fencing-level # elements (adding, changing and removing) but not fencing-topology # elements. In such a case, removing a fencing-topology element would cause # the whole change to be rejected by pacemaker with a "permission denied" # message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 report_list: ReportItemList = [] if target_type: report_list.extend(_validate_target_typewise(target_type)) if has_errors(report_list): return report_list if validate_device_ids and devices is not None: for device_id in devices: validate_id(device_id, description="stonith id", reporter=report_list) level_el_list = _find_level_elements(topology_el, level, target_type, target_value, devices) if not level_el_list: if ignore_if_missing: return report_list report_list.append( ReportItem.error( reports.messages.CibFencingLevelDoesNotExist( level, target_type, target_value, sorted(devices) if devices else [], ))) if has_errors(report_list): return report_list for el in level_el_list: el.getparent().remove(el) return report_list
def _validate_devices(resources_el: _Element, devices, force_device=False, allow_force=True) -> ReportItemList: report_list: ReportItemList = [] if not devices: report_list.append( ReportItem.error( reports.messages.RequiredOptionsAreMissing(["stonith devices" ]))) invalid_devices = [] for dev in devices: validate_id_report_list: ReportItemList = [] validate_id(dev, description="device id", reporter=validate_id_report_list) report_list.extend(validate_id_report_list) if has_errors(validate_id_report_list): continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: report_list.append( ReportItem( severity=ReportItemSeverity( level=(ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR), force_code=(None if force_device or not allow_force else report_codes.FORCE), ), message=reports.messages.StonithResourcesDoNotExist( invalid_devices), )) return report_list
def _validate_devices(resources_el, devices, force_device=False, allow_force=True) -> ReportItemList: report_list: ReportItemList = [] if not devices: report_list.append( reports.required_options_are_missing(["stonith devices"])) invalid_devices = [] for dev in devices: validate_id_report_list: ReportItemList = [] validate_id(dev, description="device id", reporter=validate_id_report_list) report_list.extend(validate_id_report_list) if has_errors(validate_id_report_list): continue # TODO use the new finding function if not is_stonith_resource(resources_el, dev): invalid_devices.append(dev) if invalid_devices: report_list.append( reports.stonith_resources_do_not_exist( invalid_devices, ReportItemSeverity.WARNING if force_device and allow_force else ReportItemSeverity.ERROR, None if force_device or not allow_force else report_codes.FORCE_STONITH_RESOURCE_DOES_NOT_EXIST)) return report_list
def remove_levels_by_params( topology_el, level=None, target_type=None, target_value=None, devices=None, ignore_if_missing=False, ) -> ReportItemList: """ Remove specified fencing level(s) etree topology_el -- etree element to remove the levels from int|string level -- level (index) of the fencing level to remove constant target_type -- the removed fencing level target value type mixed target_value -- the removed fencing level target value Iterable devices -- list of stonith devices of the removed fencing level bool ignore_if_missing -- when True, do not report if level not found """ # Do not ever remove a fencing-topology element, even if it is empty. There # may be ACLs set in pacemaker which allow "write" for fencing-level # elements (adding, changing and removing) but not fencing-topology # elements. In such a case, removing a fencing-topology element would cause # the whole change to be rejected by pacemaker with a "permission denied" # message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 report_list: ReportItemList = [] if target_type: report_list.extend(_validate_target_typewise(target_type)) if has_errors(report_list): return report_list level_el_list = _find_level_elements(topology_el, level, target_type, target_value, devices) if not level_el_list: if ignore_if_missing: return report_list report_list.append( ReportItem.error( reports.messages.CibFencingLevelDoesNotExist( level, target_type, target_value, devices or []))) if has_errors(report_list): return report_list for el in level_el_list: el.getparent().remove(el) return report_list
def remove_levels_by_params( lib_env: LibraryEnvironment, level=None, # TODO create a special type, so that it cannot accept any string target_type: Optional[str] = None, target_value=None, devices: Optional[Iterable[str]] = None, # TODO remove, deprecated backward compatibility layer ignore_if_missing: bool = False, # TODO remove, deprecated backward compatibility layer target_may_be_a_device: bool = False, ): """ Remove specified fencing level(s). LibraryEnvironment lib_env -- environment int|string level -- level (index) of the fencing level to remove target_type -- the removed fencing level target value type mixed target_value -- the removed fencing level target value devices -- list of stonith devices of the removed fencing level ignore_if_missing -- when True, do not report if level not found target_may_be_a_device -- enables backward compatibility mode for old CLI """ topology_el = get_fencing_topology(lib_env.get_cib()) report_list = cib_fencing_topology.remove_levels_by_params( topology_el, level, target_type, target_value, devices, ignore_if_missing, validate_device_ids=(not target_may_be_a_device), ) if not target_may_be_a_device or target_type != TARGET_TYPE_NODE: if lib_env.report_processor.report_list(report_list).has_errors: raise LibraryError() lib_env.push_cib() return # TODO remove, deprecated backward compatibility mode # CLI command parameters are: level, node, stonith, stonith... Both the # node and the stonith list are optional. If the node is ommited and the # stonith list is present, there is no way to figure it out, since there is # no specification of what the parameter is. Hence the pre-lib code tried # both. First it assumed the first parameter is a node. If that fence level # didn't exist, it assumed the first parameter is a device. Since it was # only possible to specify node as a target back then, this is enabled only # in that case. # CLI has no way to figure out what the first parameter is. Therefore, the # lib must try both cases if asked to do so. if not report.has_errors(report_list): lib_env.report_processor.report_list(report_list) lib_env.push_cib() return level_not_found = False for report_item in report_list: if (report_item.message.code == report.codes.CIB_FENCING_LEVEL_DOES_NOT_EXIST): level_not_found = True break if not level_not_found: lib_env.report_processor.report_list(report_list) raise LibraryError() target_and_devices = [target_value] if devices: target_and_devices.extend(devices) report_list_second = cib_fencing_topology.remove_levels_by_params( topology_el, level, None, None, target_and_devices, ignore_if_missing, validate_device_ids=(not target_may_be_a_device), ) if not report.has_errors(report_list_second): lib_env.report_processor.report_list(report_list_second) lib_env.push_cib() return lib_env.report_processor.report_list(report_list) lib_env.report_processor.report_list(report_list_second) raise LibraryError()