Пример #1
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.is_required("image", "container"),
        validate.value_not_empty("image", "image name"),
        validate.value_nonnegative_integer("masters"),
        validate.value_nonnegative_integer("promoted-max"),
        validate.mutually_exclusive(["masters", "promoted-max"], "container"),
        validate.value_positive_integer("replicas"),
        validate.value_positive_integer("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.run_collection_of_option_validators(
        container_options, validators) + deprecation_reports +
            validate.names_in(GENERIC_CONTAINER_OPTIONS,
                              container_options.keys(), "container",
                              report_codes.FORCE_OPTIONS, force_options))
Пример #2
0
def _validate_generic_container_options_update(docker_el, options,
                                               force_options):
    validators = [
        # image is a mandatory attribute and cannot be removed
        validate.value_not_empty("image", "image name"),
        validate.value_empty_or_valid(
            "masters", validate.value_nonnegative_integer("masters")),
        validate.value_empty_or_valid(
            "promoted-max",
            validate.value_nonnegative_integer("promoted-max")),
        validate.value_empty_or_valid(
            "replicas", validate.value_positive_integer("replicas")),
        validate.value_empty_or_valid(
            "replicas-per-host",
            validate.value_positive_integer("replicas-per-host")),
    ]
    # 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.mutually_exclusive(["masters", "promoted-max"],
                                        "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 docker_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 docker_el.get("masters")
            and options.get("masters") != ""):
        deprecation_reports.append(
            reports.prerequisite_option_must_not_be_set(
                "promoted-max", "masters", "container", "container"))

    return (validate.run_collection_of_option_validators(options, validators) +
            deprecation_reports + validate.names_in(
                # allow to remove options even if they are not allowed
                _generic_container_options | _options_to_remove(options),
                options.keys(),
                "container",
                report_codes.FORCE_OPTIONS,
                force_options))
Пример #3
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_option_is_missing(["device"]))

    supported_options = sbd.DEVICE_INITIALIZATION_OPTIONS_MAPPING.keys()

    report_item_list += names_in(supported_options, option_dict.keys())
    validator_list = [
        value_nonnegative_integer(key)
        for key in supported_options
    ]

    report_item_list += run_collection_of_option_validators(
        option_dict, validator_list
    )

    lib_env.report_processor.process_list(report_item_list)
    sbd.initialize_block_devices(
        lib_env.report_processor, lib_env.cmd_runner(), device_list, option_dict
    )
Пример #4
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))
Пример #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_container_docker_options_update(
    docker_el, options, force_options
):
    validators = [
        # image is a mandatory attribute and cannot be removed
        validate.value_not_empty("image", "image name"),
        validate.value_empty_or_valid(
            "masters",
            validate.value_nonnegative_integer("masters")
        ),
        validate.value_empty_or_valid(
            "replicas",
            validate.value_positive_integer("replicas")
        ),
        validate.value_empty_or_valid(
            "replicas-per-host",
            validate.value_positive_integer("replicas-per-host")
        ),
    ]
    return (
        validate.run_collection_of_option_validators(options, validators)
        +
        validate.names_in(
            # allow to remove options even if they are not allowed
            _docker_options | _options_to_remove(options),
            options.keys(),
            "container",
            report_codes.FORCE_OPTIONS,
            force_options
        )
    )
Пример #7
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_option_is_missing(["device"]))

    supported_options = sbd.DEVICE_INITIALIZATION_OPTIONS_MAPPING.keys()

    report_item_list += names_in(supported_options, option_dict.keys())
    validator_list = [
        value_nonnegative_integer(key)
        for key in supported_options
    ]

    report_item_list += run_collection_of_option_validators(
        option_dict, validator_list
    )

    lib_env.report_processor.process_list(report_item_list)
    sbd.initialize_block_devices(
        lib_env.report_processor, lib_env.cmd_runner(), device_list, option_dict
    )
Пример #8
0
 def test_report_invalid_value(self):
     assert_report_item_list_equal(
         validate.value_nonnegative_integer("key")({
             "key": "-10"
         }), [
             (severities.ERROR, report_codes.INVALID_OPTION_VALUE, {
                 "option_name": "key",
                 "option_value": "-10",
                 "allowed_values": "a non-negative integer",
             }, None),
         ])
Пример #9
0
def _validate_container_docker_options_new(options, force_options):
    validators = [
        validate.is_required("image", "container"),
        validate.value_not_empty("image", "image name"),
        validate.value_nonnegative_integer("masters"),
        validate.value_positive_integer("replicas"),
        validate.value_positive_integer("replicas-per-host"),
    ]
    return (validate.run_collection_of_option_validators(options, validators) +
            validate.names_in(_docker_options, options.keys(), "container",
                              report_codes.FORCE_OPTIONS, force_options))
Пример #10
0
def _validate_generic_container_options_new(options, force_options):
    validators = [
        validate.is_required("image", "container"),
        validate.value_not_empty("image", "image name"),
        validate.value_nonnegative_integer("masters"),
        validate.value_nonnegative_integer("promoted-max"),
        validate.mutually_exclusive(["masters", "promoted-max"], "container"),
        validate.value_positive_integer("replicas"),
        validate.value_positive_integer("replicas-per-host"),
    ]
    deprecation_reports = []
    if "masters" in options:
        deprecation_reports.append(
            reports.deprecated_option("masters", ["promoted-max"],
                                      "container",
                                      severity=ReportItemSeverity.WARNING))
    return (validate.run_collection_of_option_validators(options, validators) +
            deprecation_reports + validate.names_in(
                _generic_container_options, options.keys(), "container",
                report_codes.FORCE_OPTIONS, force_options))
Пример #11
0
 def test_report_invalid_value(self):
     assert_report_item_list_equal(
         validate.value_nonnegative_integer("key")({"key": "-10"}),
         [
             (
                 severities.ERROR,
                 report_codes.INVALID_OPTION_VALUE,
                 {
                     "option_name": "key",
                     "option_value": "-10",
                     "allowed_values": "a non-negative integer",
                 },
                 None
             ),
         ]
     )
Пример #12
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
Пример #13
0
 def test_empty_report_on_valid_option(self):
     assert_report_item_list_equal(
         validate.value_nonnegative_integer("key")({
             "key": "10"
         }), [])
Пример #14
0
def create_totem(options):
    """
    Validate creating the "totem" section

    dict options -- totem options
    """
    # No need to support force:
    # * values are either bool 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 = [
        "consensus",
        "downcheck",
        "fail_recv_const",
        "heartbeat_failures_allowed",
        "hold",
        "join",
        "max_messages",
        "max_network_delay",
        "merge",
        "miss_count_const",
        "send_join",
        "seqno_unchanged_const",
        "token",
        "token_coefficient",
        "token_retransmit",
        "token_retransmits_before_loss_const",
        "window_size",
    ]
    validators = [
        validate.value_nonnegative_integer("consensus"),
        validate.value_nonnegative_integer("downcheck"),
        validate.value_nonnegative_integer("fail_recv_const"),
        validate.value_nonnegative_integer("heartbeat_failures_allowed"),
        validate.value_nonnegative_integer("hold"),
        validate.value_nonnegative_integer("join"),
        validate.value_nonnegative_integer("max_messages"),
        validate.value_nonnegative_integer("max_network_delay"),
        validate.value_nonnegative_integer("merge"),
        validate.value_nonnegative_integer("miss_count_const"),
        validate.value_nonnegative_integer("send_join"),
        validate.value_nonnegative_integer("seqno_unchanged_const"),
        validate.value_nonnegative_integer("token"),
        validate.value_nonnegative_integer("token_coefficient"),
        validate.value_nonnegative_integer("token_retransmit"),
        validate.value_nonnegative_integer(
            "token_retransmits_before_loss_const"
        ),
        validate.value_nonnegative_integer("window_size"),
    ]
    report_items = (
        validate.run_collection_of_option_validators(options, validators)
        +
        validate.names_in(allowed_options, options.keys(), "totem")
    )
    return report_items
Пример #15
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
Пример #16
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
Пример #17
0
 def test_empty_report_on_valid_option(self):
     assert_report_item_list_equal(
         validate.value_nonnegative_integer("key")({"key": "10"}),
         []
     )