Esempio n. 1
0
    def add_quorum_device(
        self, model, model_options, generic_options, heuristics_options
    ):
        # pylint: disable=too-many-locals
        """
        Add quorum device configuration

        string model -- quorum device model
        dict model_options -- model specific options
        dict generic_options -- generic quorum device options
        dict heuristics_options -- heuristics options
        """
        if self.has_quorum_device():
            raise LibraryError(reports.qdevice_already_defined())

        # configuration cleanup
        remove_need_stopped_cluster = {
            name: ""
            for name in constants.QUORUM_OPTIONS_INCOMPATIBLE_WITH_QDEVICE
        }
        # remove old device settings
        quorum_section_list = self.__ensure_section(self.config, "quorum")
        for quorum in quorum_section_list:
            for device in quorum.get_sections("device"):
                quorum.del_section(device)
            for name, value in quorum.get_attributes():
                if (
                    name in remove_need_stopped_cluster
                    and
                    value not in ["", "0"]
                ):
                    self._need_stopped_cluster = True
        # remove conflicting quorum options
        attrs_to_remove = {
            "allow_downscale": "",
            "two_node": "",
        }
        attrs_to_remove.update(remove_need_stopped_cluster)
        self.__set_section_options(quorum_section_list, attrs_to_remove)
        # remove nodes' votes
        for nodelist in self.config.get_sections("nodelist"):
            for node_section in nodelist.get_sections("node"):
                node_section.del_attributes_by_name("quorum_votes")

        # add new configuration
        quorum = quorum_section_list[-1]
        new_device = config_parser.Section("device")
        quorum.add_section(new_device)
        self.__set_section_options([new_device], generic_options)
        new_device.set_attribute("model", model)
        new_model = config_parser.Section(model)
        self.__set_section_options([new_model], model_options)
        new_device.add_section(new_model)
        new_heuristics = config_parser.Section("heuristics")
        self.__set_section_options([new_heuristics], heuristics_options)
        new_device.add_section(new_heuristics)

        self.__update_qdevice_votes()
        self.__update_two_node()
        self.__remove_empty_sections(self.config)
Esempio n. 2
0
    def add_quorum_device(
        self, model, model_options, generic_options, heuristics_options
    ):
        # pylint: disable=too-many-locals
        """
        Add quorum device configuration

        string model -- quorum device model
        dict model_options -- model specific options
        dict generic_options -- generic quorum device options
        dict heuristics_options -- heuristics options
        """
        if self.has_quorum_device():
            raise LibraryError(reports.qdevice_already_defined())

        # configuration cleanup
        remove_need_stopped_cluster = {
            name: ""
            for name in constants.QUORUM_OPTIONS_INCOMPATIBLE_WITH_QDEVICE
        }
        # remove old device settings
        quorum_section_list = self.__ensure_section(self.config, "quorum")
        for quorum in quorum_section_list:
            for device in quorum.get_sections("device"):
                quorum.del_section(device)
            for name, value in quorum.get_attributes():
                if (
                    name in remove_need_stopped_cluster
                    and
                    value not in ["", "0"]
                ):
                    self._need_stopped_cluster = True
        # remove conflicting quorum options
        attrs_to_remove = {
            "allow_downscale": "",
            "two_node": "",
        }
        attrs_to_remove.update(remove_need_stopped_cluster)
        self.__set_section_options(quorum_section_list, attrs_to_remove)
        # remove nodes' votes
        for nodelist in self.config.get_sections("nodelist"):
            for node_section in nodelist.get_sections("node"):
                node_section.del_attributes_by_name("quorum_votes")

        # add new configuration
        quorum = quorum_section_list[-1]
        new_device = config_parser.Section("device")
        quorum.add_section(new_device)
        self.__set_section_options([new_device], generic_options)
        new_device.set_attribute("model", model)
        new_model = config_parser.Section(model)
        self.__set_section_options([new_model], model_options)
        new_device.add_section(new_model)
        new_heuristics = config_parser.Section("heuristics")
        self.__set_section_options([new_heuristics], heuristics_options)
        new_device.add_section(new_heuristics)

        self.__update_qdevice_votes()
        self.__update_two_node()
        self.__remove_empty_sections(self.config)
Esempio n. 3
0
    def add_quorum_device(
        self, report_processor, model, model_options, generic_options,
        heuristics_options, force_model=False, force_options=False,
    ):
        """
        Add quorum device configuration

        string model -- quorum device model
        dict model_options -- model specific options
        dict generic_options -- generic quorum device options
        dict heuristics_options -- heuristics options
        bool force_model -- continue even if the model is not valid
        bool force_options -- continue even if options are not valid
        """
        # validation
        if self.has_quorum_device():
            raise LibraryError(reports.qdevice_already_defined())
        report_processor.process_list(
            self.__validate_quorum_device_model(model, force_model)
            +
            self.__validate_quorum_device_model_options(
                model,
                model_options,
                need_required=True,
                force=force_options
            )
            +
            self.__validate_quorum_device_generic_options(
                generic_options,
                force=force_options
            )
            +
            self.__validate_quorum_device_add_heuristics(
                heuristics_options,
                force_options=force_options
            )
        )

        # configuration cleanup
        remove_need_stopped_cluster = dict([
            (name, "")
            for name in self.__class__.QUORUM_OPTIONS_INCOMPATIBLE_WITH_QDEVICE
        ])
        # remove old device settings
        quorum_section_list = self.__ensure_section(self.config, "quorum")
        for quorum in quorum_section_list:
            for device in quorum.get_sections("device"):
                quorum.del_section(device)
            for name, value in quorum.get_attributes():
                if (
                    name in remove_need_stopped_cluster
                    and
                    value not in ["", "0"]
                ):
                    self._need_stopped_cluster = True
        # remove conflicting quorum options
        attrs_to_remove = {
            "allow_downscale": "",
            "two_node": "",
        }
        attrs_to_remove.update(remove_need_stopped_cluster)
        self.__set_section_options(quorum_section_list, attrs_to_remove)
        # remove nodes' votes
        for nodelist in self.config.get_sections("nodelist"):
            for node in nodelist.get_sections("node"):
                node.del_attributes_by_name("quorum_votes")

        # add new configuration
        quorum = quorum_section_list[-1]
        new_device = config_parser.Section("device")
        quorum.add_section(new_device)
        self.__set_section_options([new_device], generic_options)
        new_device.set_attribute("model", model)
        new_model = config_parser.Section(model)
        self.__set_section_options([new_model], model_options)
        new_device.add_section(new_model)
        new_heuristics = config_parser.Section("heuristics")
        self.__set_section_options([new_heuristics], heuristics_options)
        new_device.add_section(new_heuristics)

        if self.__is_heuristics_enabled_with_no_exec():
            report_processor.process(
                reports.corosync_quorum_heuristics_enabled_with_no_exec()
            )

        self.__update_qdevice_votes()
        self.__update_two_node()
        self.__remove_empty_sections(self.config)
Esempio n. 4
0
    def add_quorum_device(
        self, report_processor, model, model_options, generic_options,
        force_model=False, force_options=False,
    ):
        """
        Add quorum device configuration
        model quorum device model
        model_options model specific options dict
        generic_options generic quorum device options dict
        force_model continue even if the model is not valid
        force_options continue even if options are not valid
        """
        # validation
        if self.has_quorum_device():
            raise LibraryError(reports.qdevice_already_defined())
        report_processor.process_list(
            self.__validate_quorum_device_model(model, force_model)
            +
            self.__validate_quorum_device_model_options(
                model,
                model_options,
                need_required=True,
                force=force_options
            )
            +
            self.__validate_quorum_device_generic_options(
                generic_options,
                force=force_options
            )
        )

        # configuration cleanup
        remove_need_stopped_cluster = dict([
            (name, "")
            for name in self.__class__.QUORUM_OPTIONS_INCOMPATIBLE_WITH_QDEVICE
        ])
        # remove old device settings
        quorum_section_list = self.__ensure_section(self.config, "quorum")
        for quorum in quorum_section_list:
            for device in quorum.get_sections("device"):
                quorum.del_section(device)
            for name, value in quorum.get_attributes():
                if (
                    name in remove_need_stopped_cluster
                    and
                    value not in ["", "0"]
                ):
                    self._need_stopped_cluster = True
        # remove conflicting quorum options
        attrs_to_remove = {
            "allow_downscale": "",
            "two_node": "",
        }
        attrs_to_remove.update(remove_need_stopped_cluster)
        self.__set_section_options(quorum_section_list, attrs_to_remove)
        # remove nodes' votes
        for nodelist in self.config.get_sections("nodelist"):
            for node in nodelist.get_sections("node"):
                node.del_attributes_by_name("quorum_votes")

        # add new configuration
        quorum = quorum_section_list[-1]
        new_device = config_parser.Section("device")
        quorum.add_section(new_device)
        self.__set_section_options([new_device], generic_options)
        new_device.set_attribute("model", model)
        new_model = config_parser.Section(model)
        self.__set_section_options([new_model], model_options)
        new_device.add_section(new_model)
        self.__update_qdevice_votes()
        self.__update_two_node()
        self.__remove_empty_sections(self.config)
Esempio n. 5
0
def add_device(lib_env,
               model,
               model_options,
               generic_options,
               heuristics_options,
               force_model=False,
               force_options=False,
               skip_offline_nodes=False):
    """
    Add a quorum device to a cluster, distribute and reload configs if live

    string model -- quorum device model
    dict model_options -- model specific options
    dict generic_options -- generic quorum device options
    dict heuristics_options -- heuristics options
    bool force_model -- continue even if the model is not valid
    bool force_options -- continue even if options are not valid
    bool skip_offline_nodes -- continue even if not all nodes are accessible
    """
    cfg = lib_env.get_corosync_conf()
    if cfg.has_quorum_device():
        raise LibraryError(reports.qdevice_already_defined())
    lib_env.report_processor.process_list(
        corosync_conf_validators.add_quorum_device(
            model,
            model_options,
            generic_options,
            heuristics_options, [node.nodeid for node in cfg.get_nodes()],
            force_model=force_model,
            force_options=force_options))
    cfg.add_quorum_device(
        model,
        model_options,
        generic_options,
        heuristics_options,
    )
    if cfg.is_quorum_device_heuristics_enabled_with_no_exec():
        lib_env.report_processor.process(
            reports.corosync_quorum_heuristics_enabled_with_no_exec())

    # First setup certificates for qdevice, then send corosync.conf to nodes.
    # If anything fails, nodes will not have corosync.conf with qdevice in it,
    # so there is no effect on the cluster.
    if lib_env.is_corosync_conf_live:
        target_factory = lib_env.get_node_target_factory()
        target_list = target_factory.get_target_list(
            cfg.get_nodes_names(),
            skip_non_existing=skip_offline_nodes,
        )
        # Do model specific configuration.
        # If the model is not known to pcs and was forced, do not configure
        # anything else than corosync.conf, as we do not know what to do
        # anyway.
        if model == "net":
            qdevice_net.set_up_client_certificates(
                lib_env.cmd_runner(),
                lib_env.report_processor,
                lib_env.communicator_factory,
                # We are sure the "host" key is there, it has been validated
                # above.
                target_factory.get_target_from_hostname(model_options["host"]),
                cfg.get_cluster_name(),
                target_list,
                skip_offline_nodes)

        lib_env.report_processor.process(
            reports.service_enable_started("corosync-qdevice"))
        com_cmd = qdevice_com.Enable(lib_env.report_processor,
                                     skip_offline_nodes)
        com_cmd.set_targets(target_list)
        run_and_raise(lib_env.get_node_communicator(), com_cmd)

    # everything set up, it's safe to tell the nodes to use qdevice
    lib_env.push_corosync_conf(cfg, skip_offline_nodes)

    # Now, when corosync.conf has been reloaded, we can start qdevice service.
    if lib_env.is_corosync_conf_live:
        lib_env.report_processor.process(
            reports.service_start_started("corosync-qdevice"))
        com_cmd = qdevice_com.Start(lib_env.report_processor,
                                    skip_offline_nodes)
        com_cmd.set_targets(target_list)
        run_and_raise(lib_env.get_node_communicator(), com_cmd)
Esempio n. 6
0
def add_device(
    lib_env, model, model_options, generic_options, heuristics_options,
    force_model=False, force_options=False, skip_offline_nodes=False
):
    """
    Add a quorum device to a cluster, distribute and reload configs if live

    string model -- quorum device model
    dict model_options -- model specific options
    dict generic_options -- generic quorum device options
    dict heuristics_options -- heuristics options
    bool force_model -- continue even if the model is not valid
    bool force_options -- continue even if options are not valid
    bool skip_offline_nodes -- continue even if not all nodes are accessible
    """
    cfg = lib_env.get_corosync_conf()
    if cfg.has_quorum_device():
        raise LibraryError(reports.qdevice_already_defined())

    report_processor = SimpleReportProcessor(lib_env.report_processor)
    report_processor.report_list(
        corosync_conf_validators.add_quorum_device(
            model,
            model_options,
            generic_options,
            heuristics_options,
            [node.nodeid for node in cfg.get_nodes()],
            force_model=force_model,
            force_options=force_options
        )
    )

    if lib_env.is_corosync_conf_live:
        cluster_nodes_names, report_list = get_existing_nodes_names(
            cfg,
            # Pcs is unable to communicate with nodes missing names. It cannot
            # send new corosync.conf to them. That might break the cluster.
            # Hence we error out.
            error_on_missing_name=True
        )
        report_processor.report_list(report_list)

    if report_processor.has_errors:
        raise LibraryError()

    cfg.add_quorum_device(
        model,
        model_options,
        generic_options,
        heuristics_options,
    )
    if cfg.is_quorum_device_heuristics_enabled_with_no_exec():
        lib_env.report_processor.process(
            reports.corosync_quorum_heuristics_enabled_with_no_exec()
        )

    # First setup certificates for qdevice, then send corosync.conf to nodes.
    # If anything fails, nodes will not have corosync.conf with qdevice in it,
    # so there is no effect on the cluster.
    if lib_env.is_corosync_conf_live:
        target_factory = lib_env.get_node_target_factory()
        target_list = target_factory.get_target_list(
            cluster_nodes_names, skip_non_existing=skip_offline_nodes,
        )
        # Do model specific configuration.
        # If the model is not known to pcs and was forced, do not configure
        # anything else than corosync.conf, as we do not know what to do
        # anyway.
        if model == "net":
            qdevice_net.set_up_client_certificates(
                lib_env.cmd_runner(),
                lib_env.report_processor,
                lib_env.communicator_factory,
                # We are sure the "host" key is there, it has been validated
                # above.
                target_factory.get_target_from_hostname(model_options["host"]),
                cfg.get_cluster_name(),
                target_list,
                skip_offline_nodes
            )

        lib_env.report_processor.process(
            reports.service_enable_started("corosync-qdevice")
        )
        com_cmd = qdevice_com.Enable(
            lib_env.report_processor, skip_offline_nodes
        )
        com_cmd.set_targets(target_list)
        run_and_raise(lib_env.get_node_communicator(), com_cmd)

    # everything set up, it's safe to tell the nodes to use qdevice
    lib_env.push_corosync_conf(cfg, skip_offline_nodes)

    # Now, when corosync.conf has been reloaded, we can start qdevice service.
    if lib_env.is_corosync_conf_live:
        lib_env.report_processor.process(
            reports.service_start_started("corosync-qdevice")
        )
        com_cmd = qdevice_com.Start(
            lib_env.report_processor, skip_offline_nodes
        )
        com_cmd.set_targets(target_list)
        run_and_raise(lib_env.get_node_communicator(), com_cmd)
Esempio n. 7
0
 def add_quorum_device(
     self, report_processor, model, model_options, generic_options,
     force_model=False, force_options=False,
 ):
     """
     Add quorum device configuration
     model quorum device model
     model_options model specific options dict
     generic_options generic quorum device options dict
     force_model continue even if the model is not valid
     force_options continue even if options are not valid
     """
     # validation
     if self.has_quorum_device():
         raise LibraryError(reports.qdevice_already_defined())
     report_processor.process_list(
         self.__validate_quorum_device_model(model, force_model)
         +
         self.__validate_quorum_device_model_options(
             model,
             model_options,
             need_required=True,
             force=force_options
         )
         +
         self.__validate_quorum_device_generic_options(
             generic_options,
             force=force_options
         )
     )
     # configuration cleanup
     remove_need_stopped_cluster = {
         "auto_tie_breaker": "",
         "last_man_standing": "",
         "last_man_standing_window": "",
     }
     need_stopped_cluster = False
     quorum_section_list = self.__ensure_section(self.config, "quorum")
     for quorum in quorum_section_list:
         for device in quorum.get_sections("device"):
             quorum.del_section(device)
         for name, value in quorum.get_attributes():
             if (
                 name in remove_need_stopped_cluster
                 and
                 value not in ["", "0"]
             ):
                 need_stopped_cluster = True
     attrs_to_remove = {
         "allow_downscale": "",
         "two_node": "",
     }
     attrs_to_remove.update(remove_need_stopped_cluster)
     self.__set_section_options(quorum_section_list, attrs_to_remove)
     # add new configuration
     quorum = quorum_section_list[-1]
     new_device = config_parser.Section("device")
     quorum.add_section(new_device)
     self.__set_section_options([new_device], generic_options)
     new_device.set_attribute("model", model)
     new_model = config_parser.Section(model)
     self.__set_section_options([new_model], model_options)
     new_device.add_section(new_model)
     self.__update_two_node()
     self.__remove_empty_sections(self.config)
     # update_two_node sets self._need_stopped_cluster when changing an
     # algorithm lms <-> 2nodelms. We don't care about that, it's not really
     # a change, as there was no qdevice before. So we override it.
     self._need_stopped_cluster = need_stopped_cluster