Ejemplo n.º 1
0
def validate_resource_instance_attributes_create(
    resource_agent: ResourceAgentFacade,
    instance_attributes: Mapping[str, str],
    resources_section: _Element,
    force: bool = False,
) -> reports.ReportItemList:
    report_items: reports.ReportItemList = []
    report_items += validate.ValidatorAll([
        validate.ValueNotEmpty(name, None) for name in instance_attributes
    ]).validate(instance_attributes)
    if resource_agent.metadata.agent_exists:
        report_items += validate.ValidatorAll(
            resource_agent.get_validators_allowed_parameters(force) +
            resource_agent.get_validators_required_parameters(force)).validate(
                instance_attributes)
        report_items += validate.ValidatorAll(
            resource_agent.get_validators_deprecated_parameters()).validate({
                name: value
                for name, value in instance_attributes.items()
                # we create a custom report for stonith parameter "action"
                if not (resource_agent.metadata.name.is_stonith
                        and name == "action")
            })

    if resource_agent.metadata.name.is_stonith:
        report_items += _validate_stonith_action(instance_attributes, force)

    if resource_agent.metadata.agent_exists:
        report_items += _validate_unique_instance_attributes(
            resource_agent.metadata,
            instance_attributes,
            resources_section,
            force=force,
        )
    return report_items
Ejemplo n.º 2
0
def _validate_network_options_update(bundle_el, network_el, options,
                                     force_options):
    report_list = []
    inner_primitive = get_inner_resource(bundle_el)
    if (inner_primitive is not None and
            not _is_pcmk_remote_acccessible_after_update(network_el, options)):
        report_list.append(
            reports.get_problem_creator(
                report_codes.FORCE_OPTIONS,
                force_options)(reports.resource_in_bundle_not_accessible,
                               bundle_el.get("id"), inner_primitive.get("id")))

    kwargs = validate.set_warning(report_codes.FORCE_OPTIONS, force_options)
    validators_optional_options = [
        # TODO add validators for other keys (ip-range-start - IPv4)
        validate.ValuePortNumber("control-port"),
        # Leaving a possibility to force this validation for the case pacemaker
        # starts supporting IPv6 or other format of the netmask.
        ValueHostNetmask("host-netmask", **kwargs),
    ]
    for val in validators_optional_options:
        val.empty_string_valid = True
    validators = [
        validate.NamesIn(
            # allow to remove options even if they are not allowed
            NETWORK_OPTIONS | _options_to_remove(options),
            option_type="network",
            **kwargs)
    ] + validators_optional_options

    return (report_list + validate.ValidatorAll(validators).validate(options))
Ejemplo n.º 3
0
def _validate_generic_container_options(container_options,
                                        force_options=False):
    validators = [
        validate.NamesIn(
            GENERIC_CONTAINER_OPTIONS,
            option_type="container",
            **validate.set_warning(report_codes.FORCE_OPTIONS, force_options),
        ),
        validate.IsRequiredAll(["image"], option_type="container"),
        validate.ValueNotEmpty("image", "image name"),
        validate.ValueNonnegativeInteger("masters"),
        validate.ValueNonnegativeInteger("promoted-max"),
        validate.MutuallyExclusive(
            ["masters", "promoted-max"],
            option_type="container",
        ),
        validate.ValuePositiveInteger("replicas"),
        validate.ValuePositiveInteger("replicas-per-host"),
    ]

    deprecation_reports = []
    if "masters" in container_options:
        deprecation_reports.append(
            ReportItem.warning(
                reports.messages.DeprecatedOption(
                    "masters",
                    ["promoted-max"],
                    "container",
                )))

    return (validate.ValidatorAll(validators).validate(container_options) +
            deprecation_reports)
Ejemplo n.º 4
0
def _validate_port_map_list(options_list, id_provider, force_options):
    kwargs = validate.set_warning(report_codes.FORCE_OPTIONS, force_options)
    option_type = "port-map"
    validators = [
        validate.NamesIn(PORT_MAP_OPTIONS, option_type=option_type, **kwargs),
        validate.ValueId("id",
                         option_name_for_report="port-map id",
                         id_provider=id_provider),
        validate.DependsOnOption(
            ["internal-port"],
            "port",
            option_type=option_type,
            prerequisite_type=option_type,
        ),
        validate.IsRequiredSome(["port", "range"], option_type=option_type),
        validate.MutuallyExclusive(["port", "range"], option_type=option_type),
        validate.ValuePortNumber("port"),
        validate.ValuePortNumber("internal-port"),
        validate.ValuePortRange("range", **kwargs),
    ]
    validator_all = validate.ValidatorAll(validators)

    report_list = []
    for options in options_list:
        report_list.extend(validator_all.validate(options))
    return report_list
Ejemplo n.º 5
0
def _validate_storage_map_list(options_list, id_provider, force_options):
    kwargs = validate.set_warning(report_codes.FORCE_OPTIONS, force_options)
    option_type = "storage-map"
    validators = [
        validate.NamesIn(STORAGE_MAP_OPTIONS,
                         option_type=option_type,
                         **kwargs),
        validate.ValueId(
            "id",
            option_name_for_report="storage-map id",
            id_provider=id_provider,
        ),
        validate.IsRequiredSome(
            ["source-dir", "source-dir-root"],
            option_type=option_type,
        ),
        validate.MutuallyExclusive(
            ["source-dir", "source-dir-root"],
            option_type=option_type,
        ),
        validate.IsRequiredAll(["target-dir"], option_type=option_type),
    ]
    validator_all = validate.ValidatorAll(validators)

    report_list = []
    for options in options_list:
        report_list.extend(validator_all.validate(options))
    return report_list
Ejemplo n.º 6
0
def initialize_block_devices(lib_env, device_list, option_dict):
    """
    Initialize SBD devices in device_list with options_dict.

    lib_env -- LibraryEnvironment
    device_list -- list of strings
    option_dict -- dictionary
    """
    report_item_list = []
    if not device_list:
        report_item_list.append(
            reports.required_options_are_missing(["device"]))

    supported_options = sbd.DEVICE_INITIALIZATION_OPTIONS_MAPPING.keys()

    report_item_list += (
        validate.NamesIn(supported_options).validate(option_dict))

    report_item_list += validate.ValidatorAll([
        validate.ValueNonnegativeInteger(key) for key in supported_options
    ]).validate(option_dict)

    if lib_env.report_processor.report_list(report_item_list).has_errors:
        raise LibraryError()
    sbd.initialize_block_devices(lib_env.report_processor,
                                 lib_env.cmd_runner(), device_list,
                                 option_dict)
Ejemplo n.º 7
0
def validate_operation_list(operation_list,
                            allowed_operation_name_list,
                            allow_invalid=False):
    kwargs = validate.set_warning(report_codes.FORCE_OPTIONS, allow_invalid)
    option_type = "resource operation"

    validators = [
        validate.NamesIn(ATTRIBUTES, option_type=option_type),
        validate.IsRequiredAll(["name"], option_type=option_type),
        validate.ValueIn(
            "name",
            allowed_operation_name_list,
            option_name_for_report="operation name",
            **kwargs,
        ),
        validate.ValueIn("role", RESOURCE_ROLES),
        validate.ValueIn("on-fail", ON_FAIL_VALUES),
        validate.ValueIn("record-pending", BOOLEAN_VALUES),
        validate.ValueIn("enabled", BOOLEAN_VALUES),
        validate.MutuallyExclusive(["interval-origin", "start-delay"],
                                   option_type=option_type),
        validate.ValueId("id", option_name_for_report="operation id"),
    ]
    validator_all = validate.ValidatorAll(validators)

    report_list = []
    for operation in operation_list:
        report_list.extend(validator_all.validate(operation))
    return report_list
Ejemplo n.º 8
0
Archivo: sbd.py Proyecto: nrwahl2/pcs
def _validate_sbd_options(sbd_config,
                          allow_unknown_opts=False,
                          allow_invalid_option_values=False):
    """
    Validate user SBD configuration. Options 'SBD_WATCHDOG_DEV' and 'SBD_OPTS'
    are restricted. Returns list of ReportItem

    sbd_config -- dictionary in format: <SBD config option>: <value>
    allow_unknown_opts -- if True, accept also unknown options.
    """
    validators = [
        validate.NamesIn(
            ALLOWED_SBD_OPTION_LIST,
            banned_name_list=UNSUPPORTED_SBD_OPTION_LIST,
            **validate.set_warning(report_codes.FORCE_OPTIONS,
                                   allow_unknown_opts),
        ),
        validate.ValueNonnegativeInteger("SBD_WATCHDOG_TIMEOUT"),
        validate.ValueIn(
            "SBD_TIMEOUT_ACTION",
            TIMEOUT_ACTION_ALLOWED_VALUE_LIST,
            **validate.set_warning(report_codes.FORCE_OPTIONS,
                                   allow_invalid_option_values),
        ),
    ]
    return validate.ValidatorAll(validators).validate(sbd_config)
Ejemplo n.º 9
0
    def _validate_node_attr_expr(self,
                                 expr: NodeAttrExpr) -> reports.ReportItemList:
        if not self._allow_node_attr_expr:
            self._disallowed_expr_list.add(CibRuleExpressionType.EXPRESSION)
            return []

        validator_list: List[validate.ValidatorInterface] = []
        if expr.attr_type == NODE_ATTR_TYPE_INTEGER:
            validator_list.append(
                validate.ValueInteger(
                    "attr_value", option_name_for_report="integer attribute"))
        elif expr.attr_type == NODE_ATTR_TYPE_NUMBER:
            # rhbz#1869399
            # Originally, pacemaker only supported 'number', treated it as an
            # integer and documented it as 'integer'. With CIB schema 3.5.0+,
            # 'integer' is supported as well. With crm_feature_set 3.5.0+,
            # 'number' is treated as a floating point number.
            # Since pcs never supported 'number' until the above changes in
            # pacemaker happened and pacemaker was able to handle floating
            # point numbers before (even though truncating them to integers),
            # we'll just check for a float here. If that's not good enough, we
            # can fix it later and validate the value as integer when
            # crm_feature_set < 3.5.0.
            validator_list.append(
                validate.ValueFloat("attr_value",
                                    option_name_for_report="number attribute"))
        elif expr.attr_type == NODE_ATTR_TYPE_VERSION:
            validator_list.append(
                validate.ValueVersion(
                    "attr_value", option_name_for_report="version attribute"))
        return validate.ValidatorAll(validator_list).validate(
            dataclasses.asdict(expr))
Ejemplo n.º 10
0
def _validate_generic_container_options_update(container_el, options,
                                               force_options):
    validators_optional_options = [
        validate.ValueNonnegativeInteger("masters"),
        validate.ValueNonnegativeInteger("promoted-max"),
        validate.ValuePositiveInteger("replicas"),
        validate.ValuePositiveInteger("replicas-per-host"),
    ]
    for val in validators_optional_options:
        val.empty_string_valid = True
    validators = [
        validate.NamesIn(
            # allow to remove options even if they are not allowed
            GENERIC_CONTAINER_OPTIONS | _options_to_remove(options),
            option_type="container",
            **validate.set_warning(report_codes.FORCE_OPTIONS, force_options)),
        # image is a mandatory attribute and cannot be removed
        validate.ValueNotEmpty("image", "image name")
    ] + validators_optional_options

    # CIB does not allow both to be set. Deleting both is not a problem,
    # though. Deleting one while setting another also works and is further
    # checked bellow.
    if not (options.get("masters", "") == ""
            or options.get("promoted-max", "") == ""):
        validators.append(
            validate.MutuallyExclusive(
                ["masters", "promoted-max"],
                option_type="container",
            ))

    deprecation_reports = []
    if options.get("masters"):
        # If the user wants to delete the masters option, do not report it is
        # deprecated. They may be removing it because they just found out it is
        # deprecated.
        deprecation_reports.append(
            reports.deprecated_option("masters", ["promoted-max"],
                                      "container",
                                      severity=ReportItemSeverity.WARNING))
    # Do not allow to set masters if promoted-max is set unless promoted-max is
    # going to be removed now. Do the same check also the other way around. CIB
    # only allows one of them to be set.
    if (options.get("masters") and container_el.get("promoted-max")
            and options.get("promoted-max") != ""):
        deprecation_reports.append(
            reports.prerequisite_option_must_not_be_set(
                "masters", "promoted-max", "container", "container"))
    if (options.get("promoted-max") and container_el.get("masters")
            and options.get("masters") != ""):
        deprecation_reports.append(
            reports.prerequisite_option_must_not_be_set(
                "promoted-max", "masters", "container", "container"))

    return (validate.ValidatorAll(validators).validate(options) +
            deprecation_reports)
Ejemplo n.º 11
0
def _validate_network_options_new(options, force_options):
    kwargs = validate.set_warning(report_codes.FORCE_OPTIONS, force_options)
    validators = [
        # TODO add validators for other keys (ip-range-start - IPv4)
        validate.NamesIn(NETWORK_OPTIONS, option_type="network", **kwargs),
        validate.ValuePortNumber("control-port"),
        # Leaving a possibility to force this validation for the case pacemaker
        # starts supporting IPv6 or other format of the netmask.
        ValueHostNetmask("host-netmask", **kwargs),
    ]
    return validate.ValidatorAll(validators).validate(options)
Ejemplo n.º 12
0
def _validate_ticket_options(options, allow_unknown_options):
    validator_list = ([
        validate.NamesIn(constants.TICKET_KEYS,
                         option_type="booth ticket",
                         banned_name_list=constants.GLOBAL_KEYS,
                         **validate.set_warning(report_codes.FORCE_OPTIONS,
                                                allow_unknown_options)),
    ] + [validate.ValueNotEmpty(option, None) for option in options])
    normalized_options = validate.values_to_pairs(
        options, lambda key, value: value.strip())
    return validate.ValidatorAll(validator_list).validate(normalized_options)
Ejemplo n.º 13
0
    def validate(self, force_options: bool = False) -> reports.ReportItemList:
        report_list: reports.ReportItemList = []

        # Nvpair dict is intentionally not validated: it may contain any keys
        # and values. This can change in the future and then we add a
        # validation. Until then there is really nothing to validate there.

        # validate nvset options
        validators = [
            validate.NamesIn(
                ("id", "score"),
                severity=reports.item.get_severity(reports.codes.FORCE_OPTIONS,
                                                   force_options),
            ),
            # with id_provider it validates that the id is available as well
            validate.ValueId("id",
                             option_name_for_report="id",
                             id_provider=self._id_provider),
            validate.ValueScore("score"),
        ]
        report_list.extend(
            validate.ValidatorAll(validators).validate(self._nvset_options))

        # parse and validate rule
        # TODO write and call parsed rule validation and cleanup and tests
        if self._nvset_rule:
            try:
                # Allow flags are set to True always, the parsed rule tree is
                # checked in the validator instead. That gives us better error
                # messages, such as "op expression cannot be used in this
                # context" instead of a universal "parse error".
                self._nvset_rule_parsed = parse_rule(self._nvset_rule,
                                                     allow_rsc_expr=True,
                                                     allow_op_expr=True)
                report_list.extend(
                    RuleValidator(
                        self._nvset_rule_parsed,
                        allow_rsc_expr=self._allow_rsc_expr,
                        allow_op_expr=self._allow_op_expr,
                    ).get_reports())
            except RuleParseError as e:
                report_list.append(
                    reports.ReportItem.error(
                        reports.messages.RuleExpressionParseError(
                            e.rule_string,
                            e.msg,
                            e.rule_line,
                            e.lineno,
                            e.colno,
                            e.pos,
                        )))

        return report_list
Ejemplo n.º 14
0
def validate_set_as_guest(tree, existing_nodes_names, existing_nodes_addrs,
                          node_name, options):
    validator_list = [
        validate.NamesIn(GUEST_OPTIONS, option_type="guest"),
        validate.ValueTimeInterval("remote-connect-timeout"),
        validate.ValuePortNumber("remote-port"),
    ]
    return (validate.ValidatorAll(validator_list).validate(options) +
            validate.ValueNotEmpty("node name", None).validate(
                {"node name": node_name.strip()}) +
            validate_conflicts(tree, existing_nodes_names,
                               existing_nodes_addrs, node_name, options))
Ejemplo n.º 15
0
def _validate_ticket_options(options, allow_unknown_options):
    validator_list = [
        validate.NamesIn(
            constants.TICKET_KEYS,
            option_type="booth ticket",
            banned_name_list=constants.GLOBAL_KEYS,
            severity=report.item.get_severity(
                report_codes.FORCE, allow_unknown_options
            ),
        ),
    ] + [validate.ValueNotEmpty(option, None) for option in options]
    normalized_options = validate.values_to_pairs(
        options, lambda key, value: value.strip()
    )
    return validate.ValidatorAll(validator_list).validate(normalized_options)
Ejemplo n.º 16
0
    def validate(self, force_options: bool = False) -> reports.ReportItemList:
        report_list: reports.ReportItemList = []

        # Nvpair dict is intentionally not validated: it may contain any keys
        # and values. This can change in the future and then we add a
        # validation. Until then there is really nothing to validate there.

        # validate nvset options
        validators = [
            validate.NamesIn(
                ("id", "score"),
                severity=reports.item.get_severity(reports.codes.FORCE,
                                                   force_options),
            ),
            # with id_provider it validates that the id is available as well
            validate.ValueId("id",
                             option_name_for_report="id",
                             id_provider=self._id_provider),
            validate.ValueScore("score"),
        ]
        report_list.extend(
            validate.ValidatorAll(validators).validate(self._nvset_options))

        # parse and validate rule
        if self._nvset_rule:
            try:
                self._nvset_rule_parsed = parse_rule(self._nvset_rule)
                report_list.extend(
                    RuleValidator(
                        self._nvset_rule_parsed,
                        allow_rsc_expr=self._allow_rsc_expr,
                        allow_op_expr=self._allow_op_expr,
                        allow_node_attr_expr=self._allow_node_attr_expr,
                    ).get_reports())
            except RuleParseError as e:
                report_list.append(
                    reports.ReportItem.error(
                        reports.messages.RuleExpressionParseError(
                            e.rule_string,
                            e.msg,
                            e.rule_line,
                            e.lineno,
                            e.colno,
                            e.pos,
                        )))

        return report_list
Ejemplo n.º 17
0
def _validate_ticket_options(options, allow_unknown_options):
    severity = reports.item.get_severity(reports.codes.FORCE,
                                         allow_unknown_options)
    validator_list = ([
        validate.NamesIn(
            constants.TICKET_KEYS,
            option_type="booth ticket",
            banned_name_list=constants.GLOBAL_KEYS,
            severity=severity,
        ),
    ] + [
        validate.ValueNotEmpty(option, None)
        for option in options if option != "mode"
    ] + [validate.ValueIn("mode", ["auto", "manual"], severity=severity)])
    normalized_options = validate.values_to_pairs(
        options, lambda key, value: value.strip())
    return validate.ValidatorAll(validator_list).validate(normalized_options)
Ejemplo n.º 18
0
 def test_collect_all_errors_from_specifications(self):
     assert_report_item_list_equal(
         validate.ValidatorAll([
             validate.NamesIn(["x", "y"]),
             validate.MutuallyExclusive(["x", "y"]),
             validate.ValuePositiveInteger("x"),
             validate.ValueIn("y", ["a", "b"]),
         ]).validate({
             "x": "abcd",
             "y": "defg",
             "z": "hijk",
         }),
         [
             fixture.error(
                 reports.codes.INVALID_OPTIONS,
                 option_names=["z"],
                 option_type=None,
                 allowed=["x", "y"],
                 allowed_patterns=[],
             ),
             fixture.error(
                 reports.codes.MUTUALLY_EXCLUSIVE_OPTIONS,
                 option_names=["x", "y"],
                 option_type=None,
             ),
             fixture.error(
                 reports.codes.INVALID_OPTION_VALUE,
                 option_value="abcd",
                 option_name="x",
                 allowed_values="a positive integer",
                 cannot_be_empty=False,
                 forbidden_characters=None,
             ),
             fixture.error(
                 reports.codes.INVALID_OPTION_VALUE,
                 option_value="defg",
                 option_name="y",
                 allowed_values=["a", "b"],
                 cannot_be_empty=False,
                 forbidden_characters=None,
             ),
         ],
     )
Ejemplo n.º 19
0
Archivo: sbd.py Proyecto: kmalyjur/pcs
def validate_stonith_watchdog_timeout(
    stonith_watchdog_timeout: str, force: bool = False
) -> reports.ReportItemList:
    """
    Check sbd status and config when user is setting stonith-watchdog-timeout
    Returns error message if the value is unacceptable, otherwise return nothing
    to set the property

    stonith_watchdog_timeout -- value to be validated
    """
    severity = reports.get_severity(reports.codes.FORCE, force)
    if _is_device_set_local():
        return (
            [
                reports.ReportItem(
                    severity,
                    reports.messages.StonithWatchdogTimeoutCannotBeSet(
                        reports.const.SBD_SET_UP_WITH_DEVICES
                    ),
                )
            ]
            if stonith_watchdog_timeout not in ["", "0"]
            else []
        )

    if stonith_watchdog_timeout in ["", "0"]:
        return [
            reports.ReportItem(
                severity,
                reports.messages.StonithWatchdogTimeoutCannotBeUnset(
                    reports.const.SBD_SET_UP_WITHOUT_DEVICES
                ),
            )
        ]
    return validate.ValidatorAll(
        [
            _StonithWatchdogTimeoutValidator(
                "stonith-watchdog-timeout",
                _get_local_sbd_watchdog_timeout(),
                severity=severity,
            )
        ]
    ).validate({"stonith-watchdog-timeout": stonith_watchdog_timeout})
Ejemplo n.º 20
0
def _validate_options(options) -> reports.ReportItemList:
    # Pacemaker does not care currently about meaningfulness for concrete
    # constraint, so we use all attribs.
    validators = [
        validate.NamesIn(_ATTRIBUTES, option_type="set"),
        validate.ValueIn("action", const.PCMK_ACTIONS),
        validate.ValueIn("require-all", _BOOLEAN_VALUES),
        validate.ValueIn("role", const.PCMK_ROLES),
        validate.ValueIn("sequential", _BOOLEAN_VALUES),
        validate.ValueDeprecated(
            "role",
            {
                const.PCMK_ROLE_PROMOTED_LEGACY: const.PCMK_ROLE_PROMOTED,
                const.PCMK_ROLE_UNPROMOTED_LEGACY: const.PCMK_ROLE_UNPROMOTED,
            },
            reports.ReportItemSeverity.deprecation(),
        ),
    ]
    return validate.ValidatorAll(validators).validate(options)
Ejemplo n.º 21
0
def _validate_network_options_update(
    bundle_el, network_el, options, force_options
):
    report_list = []
    inner_primitive = get_inner_resource(bundle_el)
    if (
        inner_primitive is not None
        and not _is_pcmk_remote_accessible_after_update(network_el, options)
    ):
        report_list.append(
            ReportItem(
                severity=reports.item.get_severity(
                    reports.codes.FORCE,
                    force_options,
                ),
                message=reports.messages.ResourceInBundleNotAccessible(
                    bundle_el.get("id"),
                    inner_primitive.get("id"),
                ),
            )
        )

    severity = reports.item.get_severity(reports.codes.FORCE, force_options)
    validators_optional_options = [
        # TODO add validators for other keys (ip-range-start - IPv4)
        validate.ValuePortNumber("control-port"),
        # Leaving a possibility to force this validation for the case pacemaker
        # starts supporting IPv6 or other format of the netmask.
        ValueHostNetmask("host-netmask", severity=severity),
    ]
    for val in validators_optional_options:
        val.empty_string_valid = True
    validators = [
        validate.NamesIn(
            # allow to remove options even if they are not allowed
            NETWORK_OPTIONS | _options_to_remove(options),
            option_type="network",
            severity=severity,
        )
    ] + validators_optional_options

    return report_list + validate.ValidatorAll(validators).validate(options)
Ejemplo n.º 22
0
def _validate_container(container_type, container_options, force_options=False):
    if not container_type in GENERIC_CONTAINER_TYPES:
        return [
            reports.invalid_option_value(
                "container type",
                container_type,
                GENERIC_CONTAINER_TYPES,
            )
        ]

    validators = [
        validate.NamesIn(
            GENERIC_CONTAINER_OPTIONS,
            option_type="container",
            **validate.set_warning(report_codes.FORCE_OPTIONS, force_options)
        ),
        validate.IsRequiredAll(["image"], option_type="container"),
        validate.ValueNotEmpty("image", "image name"),
        validate.ValueNonnegativeInteger("masters"),
        validate.ValueNonnegativeInteger("promoted-max"),
        validate.MutuallyExclusive(
            ["masters", "promoted-max"],
            option_type="container",
        ),
        validate.ValuePositiveInteger("replicas"),
        validate.ValuePositiveInteger("replicas-per-host"),
    ]

    deprecation_reports = []
    if "masters" in container_options:
        deprecation_reports.append(
            reports.deprecated_option(
                "masters", ["promoted-max"], "container",
                severity=ReportItemSeverity.WARNING
            )
        )

    return (
        validate.ValidatorAll(validators).validate(container_options)
        +
        deprecation_reports
    )
Ejemplo n.º 23
0
def _validate_operation_list(
    operation_list, allowed_operation_name_list, allow_invalid=False
):
    severity = reports.item.get_severity(reports.codes.FORCE, allow_invalid)
    option_type = "resource operation"

    validators = [
        validate.NamesIn(ATTRIBUTES, option_type=option_type),
        validate.IsRequiredAll(["name"], option_type=option_type),
        validate.ValueIn(
            "name",
            allowed_operation_name_list,
            option_name_for_report="operation name",
            severity=severity,
        ),
        validate.ValueIn("role", const.PCMK_ROLES),
        validate.ValueDeprecated(
            "role",
            {
                const.PCMK_ROLE_PROMOTED_LEGACY: const.PCMK_ROLE_PROMOTED,
                const.PCMK_ROLE_UNPROMOTED_LEGACY: const.PCMK_ROLE_UNPROMOTED,
            },
            reports.ReportItemSeverity.deprecation(),
        ),
        validate.ValueIn("on-fail", ON_FAIL_VALUES),
        validate.ValueIn("record-pending", _BOOLEAN_VALUES),
        validate.ValueIn("enabled", _BOOLEAN_VALUES),
        validate.MutuallyExclusive(
            ["interval-origin", "start-delay"], option_type=option_type
        ),
        validate.ValueId("id", option_name_for_report="operation id"),
    ]
    validator_all = validate.ValidatorAll(validators)

    report_list = []
    for operation in operation_list:
        report_list.extend(validator_all.validate(operation))
    return report_list
Ejemplo n.º 24
0
    def _validate_datespec_expr(expr: DatespecExpr) -> reports.ReportItemList:
        # TODO This is taken from the CIB schema. There is an ongoing
        # discussion that the schema doesn't match Pacemaker Explained. Based
        # on the result of the discussion, this might need to be updated.
        part_limits = {
            "hours": (0, 23),
            "monthdays": (1, 31),
            "weekdays": (1, 7),
            "yearsdays": (1, 366),
            "months": (1, 12),
            "weeks": (1, 53),
            "years": (None, None),
            "weekyears": (None, None),
            "moon": (0, 7),
        }

        duplicate_keys = {
            key
            for key, count in Counter([pair[0]
                                       for pair in expr.date_parts]).items()
            if count > 1
        }
        validator_list: List[validate.ValidatorInterface] = [
            validate.ValuePcmkDatespecPart(name, limits[0], limits[1])
            for name, limits in sorted(part_limits.items())
        ]
        validator_list.append(
            validate.NamesIn(part_limits.keys(), option_type="datespec"))

        report_list = validate.ValidatorAll(validator_list).validate(
            dict(expr.date_parts))
        if duplicate_keys:
            report_list.append(
                reports.item.ReportItem.error(
                    message=reports.messages.RuleExpressionOptionsDuplication(
                        sorted(duplicate_keys)), ))
        return report_list
Ejemplo n.º 25
0
def prepare_options_plain(
    cib: _Element,
    report_processor: reports.ReportProcessor,
    options,
    ticket: str,
    resource_id,
):
    options = options.copy()

    report_processor.report_list(_validate_options_common(options))

    if not ticket:
        report_processor.report(
            ReportItem.error(
                reports.messages.RequiredOptionsAreMissing(["ticket"])))
    else:
        report_processor.report_list(validate_ticket_name(ticket))
    options["ticket"] = ticket

    if not resource_id:
        report_processor.report(
            ReportItem.error(
                reports.messages.RequiredOptionsAreMissing(["rsc"])))
    options["rsc"] = resource_id

    role_value_validator = validate.ValueIn("rsc-role",
                                            const.PCMK_ROLES,
                                            option_name_for_report="role")
    role_value_validator.empty_string_valid = True

    validators = [
        role_value_validator,
        validate.ValueDeprecated(
            "rsc-role",
            {
                const.PCMK_ROLE_PROMOTED_LEGACY: const.PCMK_ROLE_PROMOTED,
                const.PCMK_ROLE_UNPROMOTED_LEGACY: const.PCMK_ROLE_UNPROMOTED,
            },
            reports.ReportItemSeverity.deprecation(),
            option_name_for_report="role",
        ),
    ]
    report_processor.report_list(
        validate.ValidatorAll(validators).validate(
            validate.values_to_pairs(
                options,
                validate.option_value_normalization(
                    {"rsc-role": lambda value: value.capitalize()}),
            )))

    if report_processor.has_errors:
        raise LibraryError()

    if "rsc-role" in options:
        if options["rsc-role"]:
            options["rsc-role"] = pacemaker.role.get_value_for_cib(
                options["rsc-role"].capitalize(),
                tools.are_new_role_names_supported(cib),
            )
        else:
            del options["rsc-role"]

    return constraint.prepare_options(
        tuple(list(ATTRIB) + list(ATTRIB_PLAIN)),
        options,
        partial(
            _create_id,
            cib,
            options["ticket"],
            resource_id,
            options.get("rsc-role", ""),
        ),
        partial(tools.check_new_id_applicable, cib, DESCRIPTION),
    )
Ejemplo n.º 26
0
    def _validate_date_inrange_expr(
        expr: DateInRangeExpr, ) -> reports.ReportItemList:
        # TODO This is taken from the CIB schema. There is an ongoing
        # discussion that the schema doesn't match Pacemaker Explained. Based
        # on the result of the discussion, this might need to be updated.
        duration_parts = {
            "hours",
            "monthdays",
            "weekdays",
            "yearsdays",
            "months",
            "weeks",
            "years",
            "weekyears",
            "moon",
        }
        start_date, end_date = None, None
        report_list = []

        if expr.date_start is not None:
            try:
                start_date = dateutil_parser.isoparse(expr.date_start)
            except ValueError:
                report_list.append(
                    reports.item.ReportItem.error(
                        message=reports.messages.InvalidOptionValue(
                            "date", expr.date_start, "ISO 8601 date"), ))
        if expr.date_end is not None:
            try:
                end_date = dateutil_parser.isoparse(expr.date_end)
            except ValueError:
                report_list.append(
                    reports.item.ReportItem.error(
                        message=reports.messages.InvalidOptionValue(
                            "date", expr.date_end, "ISO 8601 date"), ))
        if (start_date is not None and end_date is not None
                and start_date >= end_date):
            report_list.append(
                reports.item.ReportItem.error(
                    message=reports.messages.
                    RuleExpressionSinceGreaterThanUntil(
                        expr.date_start,
                        # If end_date is not None, then expr.date_end is not
                        # None, but mypy does not see it.
                        cast(str, expr.date_end),
                    ), ))

        if expr.duration_parts:
            duplicate_keys = {
                key
                for key, count in Counter(
                    [pair[0] for pair in expr.duration_parts]).items()
                if count > 1
            }
            validator_list: List[validate.ValidatorInterface] = [
                validate.ValuePositiveInteger(name)
                for name in sorted(duration_parts)
            ]
            validator_list.append(
                validate.NamesIn(duration_parts, option_type="duration"))
            report_list += validate.ValidatorAll(validator_list).validate(
                dict(expr.duration_parts))
            if duplicate_keys:
                report_list.append(
                    reports.item.ReportItem.error(
                        message=reports.
                        messages.RuleExpressionOptionsDuplication(
                            sorted(duplicate_keys)), ))

        return report_list
Ejemplo n.º 27
0
def validate_resource_instance_attributes_update(
    resource_agent: ResourceAgentFacade,
    instance_attributes: Mapping[str, str],
    resource_id: str,
    resources_section: _Element,
    force: bool = False,
) -> reports.ReportItemList:
    # TODO This function currently accepts the updated resource as a string and
    # finds the corresponding xml element by itself. This is needed as the
    # function is called from old pcs code which uses dom while pcs.lib uses
    # lxml. Once resource update command is moved to pcs.lib, this function
    # will be fixed to accept the updated resource as an element instead of a
    # string.
    report_items: reports.ReportItemList = []
    current_instance_attrs = get_nvset_as_dict(
        INSTANCE_ATTRIBUTES_TAG,
        find_element_by_tag_and_id(TAG, resources_section, resource_id),
    )

    if resource_agent.metadata.agent_exists:
        report_items += validate.ValidatorAll(
            resource_agent.get_validators_allowed_parameters(force)
        ).validate(
            # Do not report unknown parameters already set in the CIB. It would
            # be confusing to report an error in an option not actually created
            # now.
            {
                name: value
                for name, value in instance_attributes.items()
                if name not in current_instance_attrs
            }
        )
        report_items += validate.ValidatorAll(
            resource_agent.get_validators_deprecated_parameters()
        ).validate(
            {
                name: value
                for name, value in instance_attributes.items()
                # Allow removing deprecated parameters
                if value != ""
                # we create a custom report for stonith parameter "action"
                and not (
                    resource_agent.metadata.name.is_stonith and name == "action"
                )
            }
        )

        # Check that required parameters have not been removed. This is
        # complicated by two facts:
        # * parameters may by deprecated by other parameters, setting one
        #   required parameter from such group is enough
        # * we only want to report errors related to attributes to be updated
        final_attrs = dict(current_instance_attrs)
        for name, value in instance_attributes.items():
            if value == "":
                final_attrs.pop(name, None)
            else:
                final_attrs[name] = value
        report_items += validate.ValidatorAll(
            # Limit validation only to parameters entered now in an update
            # command. We don't want to report missing parameters not mentioned
            # in a command now, that would be confusing to users.
            resource_agent.get_validators_required_parameters(
                force, only_parameters=instance_attributes.keys()
            )
        ).validate(final_attrs)

    if resource_agent.metadata.name.is_stonith:
        report_items += _validate_stonith_action(instance_attributes, force)

    if resource_agent.metadata.agent_exists:
        report_items += _validate_unique_instance_attributes(
            resource_agent.metadata,
            instance_attributes,
            resources_section,
            resource_id=resource_id,
            force=force,
        )
    return report_items