def node_add_guest( env, node_name, resource_id, options, allow_incomplete_distribution=False, allow_pacemaker_remote_service_fail=False, wait=False, ): """ setup resource (resource_id) as guest node and setup node as guest LibraryEnvironment env provides all for communication with externals string resource_id -- specifies resource that should be guest node dict options could contain keys remote-node, remote-port, remote-addr, remote-connect-timeout bool allow_incomplete_distribution -- is a flag for allowing successfully finish this command even if is file distribution not succeeded bool allow_pacemaker_remote_service_fail -- is a flag for allowing successfully finish this command even if starting/enabling pacemaker_remote not succeeded mixed wait is flag for controlling waiting for pacemaker iddle mechanism """ _ensure_consistently_live_env(env) env.ensure_wait_satisfiable(wait) cib = env.get_cib() current_nodes = get_nodes(env.get_corosync_conf(), cib) report_list = guest_node.validate_set_as_guest(cib, current_nodes, node_name, options) try: resource_element = find_element_by_tag_and_id(primitive.TAG, get_resources(cib), resource_id) report_list.extend(guest_node.validate_is_not_guest(resource_element)) except LibraryError as e: report_list.extend(e.args) env.report_processor.process_list(report_list) guest_node.set_as_guest( resource_element, node_name, options.get("remote-addr", None), options.get("remote-port", None), options.get("remote-connect-timeout", None), ) _prepare_pacemaker_remote_environment( env, current_nodes, guest_node.get_host_from_options(node_name, options), allow_incomplete_distribution, allow_pacemaker_remote_service_fail, ) env.push_cib(cib, wait) if wait: _ensure_resource_running(env, resource_id)
def test_set_guest_meta_correctly(self): resource_element = etree.fromstring('<primitive id="A"/>') guest_node.set_as_guest(resource_element, "node1", connect_timeout="10") assert_xml_equal( etree.tostring(resource_element).decode(), """ <primitive id="A"> <meta_attributes id="A-meta_attributes"> <nvpair id="A-meta_attributes-remote-connect-timeout" name="remote-connect-timeout" value="10" /> <nvpair id="A-meta_attributes-remote-node" name="remote-node" value="node1" /> </meta_attributes> </primitive> """)
def test_set_guest_meta_correctly(self): resource_element = etree.fromstring('<primitive id="A"/>') guest_node.set_as_guest( resource_element, IdProvider(resource_element), "node1", connect_timeout="10" ) assert_xml_equal( etree.tostring(resource_element).decode(), """ <primitive id="A"> <meta_attributes id="A-meta_attributes"> <nvpair id="A-meta_attributes-remote-connect-timeout" name="remote-connect-timeout" value="10" /> <nvpair id="A-meta_attributes-remote-node" name="remote-node" value="node1" /> </meta_attributes> </primitive> """ )
def node_add_guest( env: LibraryEnvironment, node_name, resource_id, options, skip_offline_nodes=False, allow_incomplete_distribution=False, allow_pacemaker_remote_service_fail=False, wait: WaitType = False, ): # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements """ Make a guest node from the specified resource LibraryEnvironment env -- provides all for communication with externals string node_name -- name of the guest node string resource_id -- specifies resource that should become a guest node dict options -- guest node options (remote-port, remote-addr, remote-connect-timeout) bool skip_offline_nodes -- if True, ignore when some nodes are offline bool allow_incomplete_distribution -- if True, allow this command to finish successfully even if file distribution did not succeed bool allow_pacemaker_remote_service_fail -- if True, allow this command to finish successfully even if starting/enabling pacemaker_remote did not succeed mixed wait -- a flag for controlling waiting for pacemaker idle mechanism """ wait_timeout = env.ensure_wait_satisfiable(wait) report_processor = env.report_processor cib = env.get_cib() id_provider = IdProvider(cib) corosync_conf: Optional[CorosyncConfigFacade] if env.is_cib_live: corosync_conf = env.get_corosync_conf() else: corosync_conf = None report_processor.report( ReportItem.info( reports.messages.CorosyncNodeConflictCheckSkipped( reports.const.REASON_NOT_LIVE_CIB, ))) ( existing_nodes_names, existing_nodes_addrs, report_list, ) = get_existing_nodes_names_addrs(corosync_conf, cib) if env.is_cib_live: # We just reported corosync checks are going to be skipped so we # shouldn't complain about errors related to corosync nodes report_processor.report_list(report_list) existing_target_list = [] if env.is_cib_live: target_factory = env.get_node_target_factory() existing_target_list, new_target_list = _get_targets_for_add( target_factory, report_processor, existing_nodes_names, [node_name], skip_offline_nodes, ) new_target = new_target_list[0] if new_target_list else None # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: if new_target: new_addr = new_target.first_addr new_addr_source = ( reports.const.DEFAULT_ADDRESS_SOURCE_KNOWN_HOSTS) else: new_addr = node_name new_addr_source = reports.const.DEFAULT_ADDRESS_SOURCE_HOST_NAME options["remote-addr"] = new_addr report_processor.report( ReportItem.info( reports.messages.UsingDefaultAddressForHost( node_name, new_addr, new_addr_source))) else: # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: known_hosts = env.get_known_hosts([node_name]) if known_hosts: new_addr = known_hosts[0].dest.addr new_addr_source = ( reports.const.DEFAULT_ADDRESS_SOURCE_KNOWN_HOSTS) else: new_addr = node_name new_addr_source = reports.const.DEFAULT_ADDRESS_SOURCE_HOST_NAME options["remote-addr"] = new_addr report_processor.report( ReportItem.info( reports.messages.UsingDefaultAddressForHost( node_name, new_addr, new_addr_source))) # validate inputs report_list = guest_node.validate_set_as_guest(cib, existing_nodes_names, existing_nodes_addrs, node_name, options) searcher = ElementSearcher(primitive.TAG, resource_id, get_resources(cib)) if searcher.element_found(): resource_element = searcher.get_element() report_list.extend(guest_node.validate_is_not_guest(resource_element)) else: report_list.extend(searcher.get_errors()) report_processor.report_list(report_list) if report_processor.has_errors: raise LibraryError() # everything validated, let's set it up guest_node.set_as_guest( resource_element, id_provider, node_name, options.get("remote-addr", None), options.get("remote-port", None), options.get("remote-connect-timeout", None), ) if env.is_cib_live: _prepare_pacemaker_remote_environment( env, report_processor, existing_target_list, new_target, node_name, skip_offline_nodes, allow_incomplete_distribution, allow_pacemaker_remote_service_fail, ) else: report_processor.report_list( _reports_skip_new_node(node_name, "not_live_cib")) env.push_cib(wait_timeout=wait_timeout) if wait_timeout >= 0: _ensure_resource_running(env, resource_id)
def node_add_guest( env, node_name, resource_id, options, skip_offline_nodes=False, allow_incomplete_distribution=False, allow_pacemaker_remote_service_fail=False, wait=False, ): """ Make a guest node from the specified resource LibraryEnvironment env -- provides all for communication with externals string resource_id -- specifies resource that should become a guest node dict options -- guest node options (remote-port, remote-addr, remote-connect-timeout) bool skip_offline_nodes -- if True, ignore when some nodes are offline bool allow_incomplete_distribution -- if True, allow this command to finish successfully even if file distribution did not succeed bool allow_pacemaker_remote_service_fail -- if True, allow this command to finish successfully even if starting/enabling pacemaker_remote did not succeed mixed wait -- a flag for controlling waiting for pacemaker idle mechanism """ # TODO # * make the node name mandatory and the node address optional # * in this function interface and comment # * in cli - do not fill the addr if not specified # * in usage and man page # * get a target factory from lib.env # * use the factory to turn node names to targets # * this will create reports for unknown node names (not authenticated) # * if the node addr is not specified, use the first addr from the matching # target # * pass the target to communication functions instead of the node name # * do not create targets again and again in each function _ensure_consistently_live_env(env) env.ensure_wait_satisfiable(wait) cib = env.get_cib() existing_nodes_names, existing_nodes_addrs = get_existing_nodes_names_addrs( env.get_corosync_conf(), cib) report_list = guest_node.validate_set_as_guest(cib, existing_nodes_names, existing_nodes_addrs, node_name, options) try: resource_element = find_element_by_tag_and_id(primitive.TAG, get_resources(cib), resource_id) report_list.extend(guest_node.validate_is_not_guest(resource_element)) except LibraryError as e: report_list.extend(e.args) env.report_processor.process_list(report_list) guest_node.set_as_guest( resource_element, node_name, options.get("remote-addr", None), options.get("remote-port", None), options.get("remote-connect-timeout", None), ) _prepare_pacemaker_remote_environment( env, existing_nodes_names, node_name, skip_offline_nodes, allow_incomplete_distribution, allow_pacemaker_remote_service_fail, ) env.push_cib(wait=wait) if wait: _ensure_resource_running(env, resource_id)
def node_add_guest( env, node_name, resource_id, options, skip_offline_nodes=False, allow_incomplete_distribution=False, allow_pacemaker_remote_service_fail=False, wait=False, ): # pylint: disable=too-many-locals """ Make a guest node from the specified resource LibraryEnvironment env -- provides all for communication with externals string node_name -- name of the guest node string resource_id -- specifies resource that should become a guest node dict options -- guest node options (remote-port, remote-addr, remote-connect-timeout) bool skip_offline_nodes -- if True, ignore when some nodes are offline bool allow_incomplete_distribution -- if True, allow this command to finish successfully even if file distribution did not succeed bool allow_pacemaker_remote_service_fail -- if True, allow this command to finish successfully even if starting/enabling pacemaker_remote did not succeed mixed wait -- a flag for controlling waiting for pacemaker idle mechanism """ env.ensure_wait_satisfiable(wait) report_processor = SimpleReportProcessor(env.report_processor) target_factory = env.get_node_target_factory() cib = env.get_cib() id_provider = IdProvider(cib) if env.is_cib_live: corosync_conf = env.get_corosync_conf() else: corosync_conf = None report_processor.report( reports.corosync_node_conflict_check_skipped("not_live_cib") ) existing_nodes_names, existing_nodes_addrs, report_list = ( get_existing_nodes_names_addrs(corosync_conf, cib) ) if env.is_cib_live: # We just reported corosync checks are going to be skipped so we # shouldn't complain about errors related to corosync nodes report_processor.report_list(report_list) existing_target_list = [] if env.is_cib_live: existing_target_list, new_target_list = _get_targets_for_add( target_factory, report_processor, existing_nodes_names, [node_name], skip_offline_nodes ) new_target = new_target_list[0] if new_target_list else None # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: new_addr = new_target.first_addr if new_target else node_name options["remote-addr"] = new_addr report_processor.report( reports.using_known_host_address_for_host(node_name, new_addr) ) else: # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: known_hosts = env.get_known_hosts([node_name]) new_addr = known_hosts[0].dest.addr if known_hosts else node_name options["remote-addr"] = new_addr report_processor.report( reports.using_known_host_address_for_host(node_name, new_addr) ) # validate inputs report_list = guest_node.validate_set_as_guest( cib, existing_nodes_names, existing_nodes_addrs, node_name, options ) searcher = ElementSearcher(primitive.TAG, resource_id, get_resources(cib)) if searcher.element_found(): resource_element = searcher.get_element() report_list.extend(guest_node.validate_is_not_guest(resource_element)) else: report_list.extend(searcher.get_errors()) report_processor.report_list(report_list) if report_processor.has_errors: raise LibraryError() # everything validated, let's set it up guest_node.set_as_guest( resource_element, id_provider, node_name, options.get("remote-addr", None), options.get("remote-port", None), options.get("remote-connect-timeout", None), ) if env.is_cib_live: _prepare_pacemaker_remote_environment( env, report_processor, existing_target_list, new_target, node_name, skip_offline_nodes, allow_incomplete_distribution, allow_pacemaker_remote_service_fail, ) else: report_processor.report_list( _reports_skip_new_node(node_name, "not_live_cib") ) env.push_cib(wait=wait) if wait: _ensure_resource_running(env, resource_id)
def node_add_guest( env, node_name, resource_id, options, skip_offline_nodes=False, allow_incomplete_distribution=False, allow_pacemaker_remote_service_fail=False, wait=False, ): # pylint: disable=too-many-locals """ Make a guest node from the specified resource LibraryEnvironment env -- provides all for communication with externals string node_name -- name of the guest node string resource_id -- specifies resource that should become a guest node dict options -- guest node options (remote-port, remote-addr, remote-connect-timeout) bool skip_offline_nodes -- if True, ignore when some nodes are offline bool allow_incomplete_distribution -- if True, allow this command to finish successfully even if file distribution did not succeed bool allow_pacemaker_remote_service_fail -- if True, allow this command to finish successfully even if starting/enabling pacemaker_remote did not succeed mixed wait -- a flag for controlling waiting for pacemaker idle mechanism """ env.ensure_wait_satisfiable(wait) report_processor = SimpleReportProcessor(env.report_processor) target_factory = env.get_node_target_factory() cib = env.get_cib() id_provider = IdProvider(cib) if env.is_cib_live: corosync_conf = env.get_corosync_conf() else: corosync_conf = None report_processor.report( reports.corosync_node_conflict_check_skipped("not_live_cib")) existing_nodes_names, existing_nodes_addrs = get_existing_nodes_names_addrs( corosync_conf, cib) existing_target_list = [] if env.is_cib_live: existing_target_list, new_target_list = _get_targets_for_add( target_factory, report_processor, existing_nodes_names, [node_name], skip_offline_nodes) new_target = new_target_list[0] if new_target_list else None # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: new_addr = new_target.first_addr if new_target else node_name options["remote-addr"] = new_addr report_processor.report( reports.using_known_host_address_for_host(node_name, new_addr)) else: # default remote-addr to an address from known-hosts if "remote-addr" not in options or options["remote-addr"] is None: known_hosts = env.get_known_hosts([node_name]) new_addr = known_hosts[0].dest.addr if known_hosts else node_name options["remote-addr"] = new_addr report_processor.report( reports.using_known_host_address_for_host(node_name, new_addr)) # validate inputs report_list = guest_node.validate_set_as_guest(cib, existing_nodes_names, existing_nodes_addrs, node_name, options) searcher = ElementSearcher(primitive.TAG, resource_id, get_resources(cib)) if searcher.element_found(): resource_element = searcher.get_element() report_list.extend(guest_node.validate_is_not_guest(resource_element)) else: report_list.extend(searcher.get_errors()) report_processor.report_list(report_list) if report_processor.has_errors: raise LibraryError() # everything validated, let's set it up guest_node.set_as_guest( resource_element, id_provider, node_name, options.get("remote-addr", None), options.get("remote-port", None), options.get("remote-connect-timeout", None), ) if env.is_cib_live: _prepare_pacemaker_remote_environment( env, report_processor, existing_target_list, new_target, node_name, skip_offline_nodes, allow_incomplete_distribution, allow_pacemaker_remote_service_fail, ) else: report_processor.report_list( _reports_skip_new_node(node_name, "not_live_cib")) env.push_cib(wait=wait) if wait: _ensure_resource_running(env, resource_id)