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)
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)
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)
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)
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)
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