Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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()