Пример #1
0
def _get_quorum_options_validators(allow_empty_values=False):
    allowed_bool = ("0", "1")
    validators = {
        "auto_tie_breaker": validate.value_in(
            "auto_tie_breaker",
            allowed_bool
        ),
        "last_man_standing": validate.value_in(
            "last_man_standing",
            allowed_bool
        ),
        "last_man_standing_window": validate.value_positive_integer(
            "last_man_standing_window"
        ),
        "wait_for_all": validate.value_in(
            "wait_for_all",
            allowed_bool
        ),
    }
    if not allow_empty_values:
        # make sure to return a list even in python3 so we can call append
        # on it
        return list(validators.values())
    return [
        validate.value_empty_or_valid(option_name, validator)
        for option_name, validator in validators.items()
    ]
Пример #2
0
def _get_qdevice_model_net_options_validators(node_ids,
                                              allow_empty_values=False,
                                              force_options=False):
    allow_extra_values = validate.allow_extra_values(
        report_codes.FORCE_OPTIONS, force_options)
    validators = {
        "connect_timeout":
        validate.value_integer_in_range("connect_timeout", 1000, 2 * 60 * 1000,
                                        **allow_extra_values),
        "force_ip_version":
        validate.value_in("force_ip_version", ("0", "4", "6"),
                          **allow_extra_values),
        "port":
        validate.value_port_number("port", **allow_extra_values),
        "tie_breaker":
        validate.value_in("tie_breaker", ["lowest", "highest"] + node_ids,
                          **allow_extra_values),
    }
    if not allow_empty_values:
        return ([
            validate.value_not_empty("host", "a qdevice host address"),
            _validate_qdevice_net_algorithm(**allow_extra_values)
        ] +
                # explicitely convert to a list for python 3
                list(validators.values()))
    return ([
        validate.value_not_empty("host", "a qdevice host address"),
        _validate_qdevice_net_algorithm(**allow_extra_values)
    ] + [
        validate.value_empty_or_valid(option_name, validator)
        for option_name, validator in validators.items()
    ])
Пример #3
0
def create_transport_udp(generic_options, compression_options, crypto_options):
    """
    Validate creating udp/udpu transport options

    dict generic_options -- generic transport options
    dict compression_options -- compression options
    dict crypto_options -- crypto options
    """
    # No need to support force:
    # * values are either an enum or numbers with no range set - nothing to
    #   force
    # * names are strictly set as we cannot risk the user overwrites some
    #   setting they should not to
    # * changes to names and values in corosync are very rare
    allowed_options = [
        "ip_version",
        "netmtu",
    ]
    validators = [
        validate.value_in("ip_version", constants.IP_VERSION_VALUES),
        validate.value_positive_integer("netmtu"),
    ]
    report_items = (validate.run_collection_of_option_validators(
        generic_options, validators) + validate.names_in(
            allowed_options, generic_options.keys(), "udp/udpu transport"))
    if compression_options:
        report_items.append(
            reports.corosync_transport_unsupported_options(
                "compression", "udp/udpu", ("knet", )))
    if crypto_options:
        report_items.append(
            reports.corosync_transport_unsupported_options(
                "crypto", "udp/udpu", ("knet", )))
    return report_items
Пример #4
0
 def __get_heuristics_options_validators(
     self, allow_empty_values=False, force_options=False
 ):
     validators = {
         "mode": validate.value_in(
             "mode",
             ("off", "on", "sync"),
             code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
             allow_extra_values=force_options
         ),
         "interval": validate.value_positive_integer(
             "interval",
             code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
             allow_extra_values=force_options
         ),
         "sync_timeout": validate.value_positive_integer(
             "sync_timeout",
             code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
             allow_extra_values=force_options
         ),
         "timeout": validate.value_positive_integer(
             "timeout",
             code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
             allow_extra_values=force_options
         ),
     }
     if not allow_empty_values:
         # make sure to return a list even in python3 so we can call append
         # on it
         return list(validators.values())
     return [
         validate.value_empty_or_valid(option_name, validator)
         for option_name, validator in validators.items()
     ]
Пример #5
0
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.value_nonnegative_integer("SBD_WATCHDOG_TIMEOUT"),
        validate.value_in(
            "SBD_TIMEOUT_ACTION",
            TIMEOUT_ACTION_ALLOWED_VALUE_LIST,
            code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
            extra_values_allowed=allow_invalid_option_values,
        ),
    ]

    return (validate.names_in(
        ALLOWED_SBD_OPTION_LIST,
        sbd_config.keys(),
        option_type=None,
        banned_name_list=UNSUPPORTED_SBD_OPTION_LIST,
        code_to_allow_extra_names=report_codes.FORCE_OPTIONS,
        extra_names_allowed=allow_unknown_opts,
    ) + validate.run_collection_of_option_validators(sbd_config, validators))
Пример #6
0
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.value_nonnegative_integer("SBD_WATCHDOG_TIMEOUT"),
        validate.value_in(
            "SBD_TIMEOUT_ACTION",
            TIMEOUT_ACTION_ALLOWED_VALUE_LIST,
            code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
            extra_values_allowed=allow_invalid_option_values,
        ),
    ]

    return (
        validate.names_in(
            ALLOWED_SBD_OPTION_LIST,
            sbd_config.keys(),
            option_type=None,
            banned_name_list=UNSUPPORTED_SBD_OPTION_LIST,
            code_to_allow_extra_names=report_codes.FORCE_OPTIONS,
            extra_names_allowed=allow_unknown_opts,
        )
        +
        validate.run_collection_of_option_validators(sbd_config, validators)

    )
Пример #7
0
 def test_returns_empty_report_on_valid_normalized_option(self):
     self.assertEqual(
         [],
         validate.value_in("a", ["b"])(
             {"a": validate.ValuePair(original="C", normalized="b")}
         ),
     )
Пример #8
0
 def test_returns_empty_report_on_valid_normalized_option(self):
     self.assertEqual(
         [],
         validate.value_in("a", ["b"])({
             "a":
             validate.ValuePair(original="C", normalized="b")
         }),
     )
Пример #9
0
 def test_returns_report_about_invalid_option(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"])({
             "a": "c"
         }), [
             (severities.ERROR, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "a",
                 "option_value": "c",
                 "allowed_values": ["b"],
             }, None),
         ])
Пример #10
0
 def test_supports_forceable_errors(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"], code_to_allow_extra_values="FORCE")({
             "a":
             "c"
         }), [
             (severities.ERROR, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "a",
                 "option_value": "c",
                 "allowed_values": ["b"],
             }, "FORCE"),
         ])
Пример #11
0
 def test_support_OptionValuePair(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"])({
             "a":
             validate.ValuePair(original="C", normalized="c")
         }), [
             (severities.ERROR, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "a",
                 "option_value": "C",
                 "allowed_values": ["b"],
             }, None),
         ])
Пример #12
0
 def test_supports_another_report_option_name(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"], option_name_for_report="option a")({
             "a":
             "c"
         }), [
             (severities.ERROR, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "option a",
                 "option_value": "c",
                 "allowed_values": ["b"],
             }, None),
         ])
Пример #13
0
def validate_operation_list(operation_list,
                            allowed_operation_name_list,
                            allow_invalid=False):
    options_validators = [
        validate.is_required("name", "resource operation"),
        validate.value_in("role", ROLE_VALUES),
        validate.value_in("requires", REQUIRES_VALUES),
        validate.value_in("on-fail", ON_FAIL_VALUES),
        validate.value_in("record-pending", BOOLEAN_VALUES),
        validate.value_in("enabled", BOOLEAN_VALUES),
        validate.mutually_exclusive(["interval-origin", "start-delay"],
                                    "resource operation"),
        validate.value_in(
            "name",
            allowed_operation_name_list,
            option_name_for_report="operation name",
            code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
            allow_extra_values=allow_invalid,
        ),
        validate.value_id("id", option_name_for_report="operation id"),
    ]
    report_list = []
    for operation in operation_list:
        report_list.extend(validate_operation(operation, options_validators))
    return report_list
Пример #14
0
def create_link_list_udp(link_list):
    """
    Validate creating udp/udpu link (interface) list options

    iterable link_list -- list of link options
    """
    if not link_list:
        # It is not mandatory to set link options. If an empty link list is
        # provided, everything is fine and we have nothing to validate.
        return []

    allowed_options = [
        "bindnetaddr",
        "broadcast",
        "mcastaddr",
        "mcastport",
        "ttl",
    ]
    validators = [
        validate.value_ip_address("bindnetaddr"),
        validate.value_in("broadcast", ("0", "1")),
        validate.value_ip_address("mcastaddr"),
        validate.value_port_number("mcastport"),
        validate.value_integer_in_range("ttl", 0, 255),
    ]
    options = link_list[0]
    report_items = (
        validate.run_collection_of_option_validators(options, validators)
        +
        validate.names_in(allowed_options, options.keys(), "link")
    )
    # default values taken from `man corosync.conf`
    if options.get("broadcast", "0") == "1" and "mcastaddr" in options:
        report_items.append(
            reports.prerequisite_option_must_be_disabled(
                "mcastaddr",
                "broadcast",
                option_type="link",
                prerequisite_type="link"
            )
        )
    link_count = len(link_list)
    if link_count > constants.LINKS_UDP_MAX:
        report_items.append(
            reports.corosync_too_many_links(
                link_count,
                constants.LINKS_UDP_MAX,
                "udp/udpu"
            )
        )
    return report_items
Пример #15
0
 def test_supports_warning(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"],
                           code_to_allow_extra_values="FORCE",
                           allow_extra_values=True)({
                               "a": "c"
                           }),
         [
             (severities.WARNING, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "a",
                 "option_value": "c",
                 "allowed_values": ["b"],
             }, None),
         ])
Пример #16
0
def prepare(
    report_processor, raw_operation_list, default_operation_list,
    allowed_operation_name_list, allow_invalid=False
):
    """
    Return operation_list prepared from raw_operation_list and
    default_operation_list.

    report_processor is tool for warning/info/error reporting
    list of dicts raw_operation_list are entered operations that require
        follow-up care
    list of dicts default_operation_list are operations defined as default by
        (most probably) resource agent
    bool allow_invalid is flag for validation skipping
    """
    operations_to_validate = [
        validate.values_to_pairs(op, normalize) for op in raw_operation_list
    ]

    report_list = []

    options_validators = OPERATION_OPTIONS_VALIDATORS + [
        validate.value_in(
            "name",
            allowed_operation_name_list,
            option_name_for_report="operation name",
            code_to_allow_extra_values=report_codes.FORCE_OPTIONS,
            allow_extra_values=allow_invalid,
        )
    ]
    for operation in operations_to_validate:
        report_list.extend(
            validate_operation(operation, options_validators)
        )

    operation_list = [
        validate.pairs_to_values(op) for op in operations_to_validate
    ]

    report_list.extend(validate_different_intervals(operation_list))

    #can raise LibraryError
    report_processor.process_list(report_list)

    return complete_all_intervals(operation_list) + get_remaining_defaults(
        report_processor,
        operation_list,
        default_operation_list
    )
Пример #17
0
 def validate_func(option_dict):
     allowed_algorithms = (
         "ffsplit",
         "lms",
     )
     value = validate.ValuePair.get(option_dict["algorithm"])
     if validate.is_empty_string(value.normalized):
         return [
             reports.invalid_option_value("algorithm", value.original,
                                          allowed_algorithms)
         ]
     return validate.value_in(
         "algorithm",
         allowed_algorithms,
         code_to_allow_extra_values=code_to_allow_extra_values,
         extra_values_allowed=extra_values_allowed)(option_dict)
Пример #18
0
 def test_returns_report_about_invalid_option(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"])({"a": "c"}),
         [
             (
                 severities.ERROR,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "a",
                     "option_value": "c",
                     "allowed_values": ["b"],
                 },
                 None
             ),
         ]
     )
Пример #19
0
def add_quorum_device(
    model, model_options, generic_options, heuristics_options, node_ids,
    force_model=False, force_options=False
):
    """
    Validate adding a quorum device

    string model -- quorum device model
    dict model_options -- model specific options
    dict generic_options -- generic quorum device options
    dict heuristics_options -- heuristics options
    list node_ids -- list of existing node ids
    bool force_model -- continue even if the model is not valid
    bool force_options -- turn forceable errors into warnings
    """
    report_items = []

    model_validators = {
        "net": lambda: _qdevice_add_model_net_options(
            model_options,
            node_ids,
            force_options
        ),
    }
    if model in model_validators:
        report_items += model_validators[model]()
    else:
        report_items += validate.run_collection_of_option_validators(
            {"model": model},
            [
                validate.value_in(
                    "model",
                    list(model_validators.keys()),
                    **validate.allow_extra_values(
                        report_codes.FORCE_QDEVICE_MODEL, force_model
                    )
                )
            ]
        )
    return (
        report_items
        +
        _qdevice_add_generic_options(generic_options, force_options)
        +
        _qdevice_add_heuristics_options(heuristics_options, force_options)
    )
Пример #20
0
 def test_support_OptionValuePair(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"])(
             {"a": validate.ValuePair(original="C", normalized="c")}
         ),
         [
             (
                 severities.ERROR,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "a",
                     "option_value": "C",
                     "allowed_values": ["b"],
                 },
                 None
             ),
         ]
     )
Пример #21
0
 def test_supports_another_report_option_name(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"], option_name_for_report="option a")(
             {"a": "c"}
         ),
         [
             (
                 severities.ERROR,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "option a",
                     "option_value": "c",
                     "allowed_values": ["b"],
                 },
                 None
             ),
         ]
     )
Пример #22
0
 def test_supports_forceable_errors(self):
     assert_report_item_list_equal(
         validate.value_in("a", ["b"], code_to_allow_extra_values="FORCE")(
             {"a": "c"}
         ),
         [
             (
                 severities.ERROR,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "a",
                     "option_value": "c",
                     "allowed_values": ["b"],
                 },
                 "FORCE"
             ),
         ]
     )
Пример #23
0
 def test_supports_warning(self):
     assert_report_item_list_equal(
         validate.value_in(
             "a",
             ["b"],
             code_to_allow_extra_values="FORCE",
             allow_extra_values=True
         )(
             {"a": "c"}
         ),
         [
             (
                 severities.WARNING,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "a",
                     "option_value": "c",
                     "allowed_values": ["b"],
                 },
                 None
             ),
         ]
     )
Пример #24
0
def create_transport_knet(generic_options, compression_options, crypto_options):
    """
    Validate creating knet transport options

    dict generic_options -- generic transport options
    dict compression_options -- compression options
    dict crypto_options -- crypto options
    """
    # No need to support force:
    # * values are either an enum or numbers with no range set - nothing to force
    # * names are strictly set as we cannot risk the user overwrites some
    #   setting they should not to
    # * changes to names and values in corosync are very rare
    generic_allowed = [
        "ip_version", # It tells knet which IP to prefer.
        "knet_pmtud_interval",
        "link_mode",
    ]
    generic_validators = [
        validate.value_in("ip_version", ("ipv4", "ipv6")),
        validate.value_nonnegative_integer("knet_pmtud_interval"),
        validate.value_in("link_mode", ("active", "passive", "rr")),
    ]
    compression_allowed = [
        "level",
        "model",
        "threshold",
    ]
    compression_validators = [
        validate.value_nonnegative_integer("level"),
        validate.value_not_empty(
            "model",
            "a compression model e.g. zlib, lz4 or bzip2"
        ),
        validate.value_nonnegative_integer("threshold"),
    ]
    crypto_type = "crypto"
    crypto_allowed = [
        "cipher",
        "hash",
        "model",
    ]
    crypto_validators = [
        validate.value_in(
            "cipher",
            ("none", "aes256", "aes192", "aes128", "3des")
        ),
        validate.value_in(
            "hash",
            ("none", "md5", "sha1", "sha256", "sha384", "sha512")
        ),
        validate.value_in("model", ("nss", "openssl")),
    ]
    report_items = (
        validate.run_collection_of_option_validators(
            generic_options,
            generic_validators
        )
        +
        validate.names_in(
            generic_allowed,
            generic_options.keys(),
            "knet transport"
        )
        +
        validate.run_collection_of_option_validators(
            compression_options,
            compression_validators
        )
        +
        validate.names_in(
            compression_allowed,
            compression_options.keys(),
            "compression"
        )
        +
        validate.run_collection_of_option_validators(
            crypto_options,
            crypto_validators
        )
        +
        validate.names_in(
            crypto_allowed,
            crypto_options.keys(),
            crypto_type
        )
    )
    if (
        # default values taken from `man corosync.conf`
        crypto_options.get("cipher", "aes256") != "none"
        and
        crypto_options.get("hash", "sha1") == "none"
    ):
        report_items.append(
            reports.prerequisite_option_must_be_enabled_as_well(
                "cipher",
                "hash",
                option_type="crypto",
                prerequisite_type="crypto"
            )
        )
    return report_items
Пример #25
0
    "true",
    "false",
]

#normalize(key, value) -> normalized_value
normalize = validate.option_value_normalization({
    "role": lambda value: value.lower().capitalize(),
    "requires": lambda value: value.lower(),
    "on-fail": lambda value: value.lower(),
    "record-pending": lambda value: value.lower(),
    "enabled": lambda value: value.lower(),
})

OPERATION_OPTIONS_VALIDATORS = [
    validate.is_required("name", "resource operation"),
    validate.value_in("role", ROLE_VALUES),
    validate.value_in("requires", REQUIRES_VALUES),
    validate.value_in("on-fail", ON_FAIL_VALUES),
    validate.value_in("record-pending", BOOLEAN_VALUES),
    validate.value_in("enabled", BOOLEAN_VALUES),
    validate.mutually_exclusive(
        ["interval-origin", "start-delay"],
        "resource operation"
    )
]

def prepare(
    report_processor, raw_operation_list, default_operation_list,
    allowed_operation_name_list, allow_invalid=False
):
    """
Пример #26
0
def _validate_container_type(container_type):
    return validate.value_in("type", ("docker", ), "container type")({
        "type":
        container_type,
    })
Пример #27
0
def create(cluster_name, node_list, transport, force_unresolvable=False):
    """
    Validate creating a new minimalistic corosync.conf

    string cluster_name -- the name of the new cluster
    list node_list -- nodes of the new cluster; dict: name, addrs
    string transport -- corosync transport used in the new cluster
    bool force_unresolvable -- if True, report unresolvable addresses as
        warnings instead of errors
    """
    # cluster name and transport validation
    validators = [
        validate.value_not_empty("name", "a non-empty string", "cluster name"),
        validate.value_in("transport", constants.TRANSPORTS_ALL)
    ]
    report_items = validate.run_collection_of_option_validators(
        {
            "name": cluster_name,
            "transport": transport
        },
        validators
    )

    # nodelist validation
    get_addr_type = _addr_type_analyzer()
    all_names_usable = True # can names be used to identifying nodes?
    all_names_count = defaultdict(int)
    all_addrs_count = defaultdict(int)
    addr_types_per_node = []
    unresolvable_addresses = set()
    # First, validate each node on its own. Also extract some info which will
    # be needed when validating the nodelist and inter-node dependencies.
    for i, node in enumerate(node_list, 1):
        report_items.extend(
            validate.run_collection_of_option_validators(
                node,
                _get_node_name_validators(i)
            )
            +
            validate.names_in(["addrs", "name"], node.keys(), "node")
        )
        if "name" in node and node["name"]:
            # Count occurrences of each node name. Do not bother counting
            # missing or empty names. They must be fixed anyway.
            all_names_count[node["name"]] += 1
        else:
            all_names_usable = False
        # Cannot use node.get("addrs", []) - if node["addrs"] == None then
        # the get returns None and len(None) raises an exception.
        addr_count = len(node.get("addrs") or [])
        if transport in (constants.TRANSPORTS_KNET + constants.TRANSPORTS_UDP):
            if transport in constants.TRANSPORTS_KNET:
                min_addr_count = constants.LINKS_KNET_MIN
                max_addr_count = constants.LINKS_KNET_MAX
            else:
                min_addr_count = constants.LINKS_UDP_MIN
                max_addr_count = constants.LINKS_UDP_MAX
            if (
                addr_count < min_addr_count
                or
                addr_count > max_addr_count
            ):
                report_items.append(
                    reports.corosync_bad_node_addresses_count(
                        addr_count,
                        min_addr_count,
                        max_addr_count,
                        node_name=node.get("name"),
                        node_index=i
                    )
                )
        addr_types = []
        # Cannot use node.get("addrs", []) - if node["addrs"] == None then
        # the get returns None and len(None) raises an exception.
        for addr in (node.get("addrs") or []):
            all_addrs_count[addr] += 1
            addr_types.append(get_addr_type(addr))
            if get_addr_type(addr) == ADDR_UNRESOLVABLE:
                unresolvable_addresses.add(addr)
        addr_types_per_node.append(addr_types)
    # Report all unresolvable addresses at once instead on each own.
    if unresolvable_addresses:
        severity = ReportItemSeverity.ERROR
        forceable = report_codes.FORCE_NODE_ADDRESSES_UNRESOLVABLE
        if force_unresolvable:
            severity = ReportItemSeverity.WARNING
            forceable = None
        report_items.append(
            reports.node_addresses_unresolvable(
                unresolvable_addresses,
                severity,
                forceable
            )
        )

    # Reporting single-node errors finished.
    # Now report nodelist and inter-node errors.
    if len(node_list) < 1:
        report_items.append(reports.corosync_nodes_missing())
    non_unique_names = set([
        name for name, count in all_names_count.items() if count > 1
    ])
    if non_unique_names:
        all_names_usable = False
        report_items.append(
            reports.node_names_duplication(non_unique_names)
        )
    non_unique_addrs = set([
        addr for addr, count in all_addrs_count.items() if count > 1
    ])
    if non_unique_addrs:
        report_items.append(
            reports.node_addresses_duplication(non_unique_addrs)
        )
    if all_names_usable:
        # Check for errors using node names in their reports. If node names are
        # ambiguous then such issues cannot be comprehensibly reported so the
        # checks are skipped.
        node_addr_count = {}
        for node in node_list:
            # Cannot use node.get("addrs", []) - if node["addrs"] == None then
            # the get returns None and len(None) raises an exception.
            node_addr_count[node["name"]] = len(node.get("addrs") or [])
        # Check if all nodes have the same number of addresses. No need to
        # check that if udp or udpu transport is used as they can only use one
        # address and that has already been checked above.
        if (
            transport not in constants.TRANSPORTS_UDP
            and
            len(Counter(node_addr_count.values()).keys()) > 1
        ):
            report_items.append(
                reports.corosync_node_address_count_mismatch(node_addr_count)
            )
    # Check mixing IPv4 and IPv6 in one link, node names are not relevant
    links_ip_mismatch = []
    for link, addr_types in enumerate(zip_longest(*addr_types_per_node)):
        if ADDR_IPV4 in addr_types and ADDR_IPV6 in addr_types:
            links_ip_mismatch.append(link)
    if links_ip_mismatch:
        report_items.append(
            reports.corosync_ip_version_mismatch_in_links(links_ip_mismatch)
        )

    return report_items
Пример #28
0
 def setUp(self):
     self.validators = {
         "a": validate.value_in("a", ["x", "y", "z"]),
         "b": validate.value_integer_in_range("b", 0, 9),
     }
Пример #29
0
 def test_returns_empty_report_on_valid_option(self):
     self.assertEqual([], validate.value_in("a", ["b"])({"a": "b"}))
Пример #30
0
 def setUp(self):
     self.validators = {
         "a": validate.value_in("a", ["x", "y", "z"]),
         "b": validate.value_integer_in_range("b", 0, 9),
     }
Пример #31
0
def create_link_list_knet(link_list, max_link_number):
    """
    Validate creating knet link (interface) list options

    iterable link_list -- list of link options
    integer max_link_number -- highest allowed linknumber
    """
    if not link_list:
        # It is not mandatory to set link options. If an empty link list is
        # provided, everything is fine and we have nothing to validate. It is
        # also possible to set link options for only some of the links.
        return []
    max_link_number = max(0, min(constants.LINKS_KNET_MAX - 1, max_link_number))
    max_link_count = max_link_number + 1
    allowed_options = [
        "ip_version", # It tells knet which IP to prefer.
        "linknumber",
        "link_priority",
        "mcastport",
        "ping_interval",
        "ping_precision",
        "ping_timeout",
        "pong_count",
        "transport",
    ]
    validators = [
        validate.value_in("ip_version", ("ipv4", "ipv6")),
        validate.value_integer_in_range("linknumber", 0, max_link_number),
        validate.value_integer_in_range("link_priority", 0, 255),
        validate.value_port_number("mcastport"),
        validate.value_nonnegative_integer("ping_interval"),
        validate.value_nonnegative_integer("ping_precision"),
        validate.value_nonnegative_integer("ping_timeout"),
        validate.depends_on_option(
            "ping_interval",
            "ping_timeout",
            option_type="link",
            prerequisite_type="link"
        ),
        validate.depends_on_option(
            "ping_timeout",
            "ping_interval",
            option_type="link",
            prerequisite_type="link"
        ),
        validate.value_nonnegative_integer("pong_count"),
        validate.value_in("transport", ("sctp", "udp")),
    ]
    report_items = []
    used_link_number = defaultdict(int)
    for options in link_list:
        if "linknumber" in options:
            used_link_number[options["linknumber"]] += 1
        report_items += (
            validate.run_collection_of_option_validators(options, validators)
            +
            validate.names_in(allowed_options, options.keys(), "link")
        )
    non_unique_linknumbers = [
        number for number, count in used_link_number.items() if count > 1
    ]
    if non_unique_linknumbers:
        report_items.append(
            reports.corosync_link_number_duplication(non_unique_linknumbers)
        )
    link_count = len(link_list)
    if link_count > max_link_count:
        report_items.append(
            reports.corosync_too_many_links(link_count, max_link_count, "knet")
        )
    return report_items
Пример #32
0
def create_link_list_knet(link_list, max_allowed_link_count):
    """
    Validate creating knet link (interface) list options

    iterable link_list -- list of link options
    integer max_allowed_link_count -- how many links is defined by addresses
    """
    if not link_list:
        # It is not mandatory to set link options. If an empty link list is
        # provided, everything is fine and we have nothing to validate. It is
        # also possible to set link options for only some of the links.
        return []

    allowed_options = [
        "linknumber",
        "link_priority",
        "mcastport",
        "ping_interval",
        "ping_precision",
        "ping_timeout",
        "pong_count",
        "transport",
    ]
    validators = [
        validate.value_integer_in_range("link_priority", 0, 255),
        validate.value_port_number("mcastport"),
        validate.value_nonnegative_integer("ping_interval"),
        validate.value_nonnegative_integer("ping_precision"),
        validate.value_nonnegative_integer("ping_timeout"),
        validate.depends_on_option("ping_interval",
                                   "ping_timeout",
                                   option_type="link",
                                   prerequisite_type="link"),
        validate.depends_on_option("ping_timeout",
                                   "ping_interval",
                                   option_type="link",
                                   prerequisite_type="link"),
        validate.value_nonnegative_integer("pong_count"),
        validate.value_in("transport", ("sctp", "udp")),
    ]
    report_items = []
    used_link_number = defaultdict(int)
    for options in link_list:
        if "linknumber" in options:
            used_link_number[options["linknumber"]] += 1
            if validate.is_integer(options["linknumber"], 0,
                                   constants.LINKS_KNET_MAX - 1):
                if int(options["linknumber"]) >= max_allowed_link_count:
                    # first link is link0, hence >=
                    report_items.append(
                        reports.corosync_link_does_not_exist_cannot_update(
                            options["linknumber"],
                            link_count=max_allowed_link_count))
            else:
                report_items.append(
                    reports.invalid_option_value(
                        "linknumber", options["linknumber"],
                        f"0..{constants.LINKS_KNET_MAX - 1}"))
        report_items += (
            validate.run_collection_of_option_validators(options, validators) +
            validate.names_in(allowed_options, options.keys(), "link"))
    non_unique_linknumbers = [
        number for number, count in used_link_number.items() if count > 1
    ]
    if non_unique_linknumbers:
        report_items.append(
            reports.corosync_link_number_duplication(non_unique_linknumbers))
    report_items.extend(
        _check_link_options_count(len(link_list), max_allowed_link_count))
    return report_items
Пример #33
0
 def test_returns_empty_report_on_valid_option(self):
     self.assertEqual(
         [],
         validate.value_in("a", ["b"])({"a": "b"})
     )
Пример #34
0
def _validate_container_type(container_type):
    return validate.value_in("type", GENERIC_CONTAINER_TYPES,
                             "container type")({
                                 "type": container_type,
                             })