def __init__(self, args): self._args = args self._proxy = ServerProxy( 'http://localhost:%d/%s/' % (get_daemon_port(), rclpy.get_rmw_implementation_identifier()), allow_none=True) self._methods = []
def main(*, argv=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '--rmw-implementation', type=str, required=True, help='The RMW implementation name (must match the return value of ' 'rclpy.get_rmw_implementation_identifier())') parser.add_argument( '--ros-domain-id', metavar='N', type=int, required=True, help='The ROS domain id (must match the environment variable ' 'ROS_DOMAIN_ID)') parser.add_argument( '--timeout', metavar='N', type=int, default=2 * 60 * 60, help='Shutdown the daemon after N seconds of inactivity') args = parser.parse_args(args=argv) # the arguments are only passed for visibility in e.g. the process list assert args.rmw_implementation == rclpy.get_rmw_implementation_identifier() assert args.ros_domain_id == get_ros_domain_id() serve(make_xmlrpc_server(), timeout=args.timeout)
def spawn_daemon(args, wait_until_spawned=None, debug=False): ros_domain_id = int(os.environ.get('ROS_DOMAIN_ID', 0)) kwargs = {} if platform.system() != 'Windows': cmd = ['_ros2_daemon'] else: # allow closing the shell the daemon was spawned from # while the daemon is still running cmd = [ sys.executable, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'daemon/__init__.py') ] # Process Creation Flag documented in the MSDN DETACHED_PROCESS = 0x00000008 # noqa: N806 kwargs.update(creationflags=DETACHED_PROCESS) # avoid showing cmd windows for subprocess si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESHOWWINDOW si.wShowWindow = subprocess.SW_HIDE kwargs['startupinfo'] = si # don't keep handle of current working directory in daemon process kwargs.update(cwd=os.environ.get('SYSTEMROOT', None)) rmw_implementation_identifier = rclpy.get_rmw_implementation_identifier() if rmw_implementation_identifier is None: raise RuntimeError('Unable to get rmw_implementation_identifier, ' 'try specifying the implementation to use via the ' "'RMW_IMPLEMENTATION' environment variable") cmd.extend([ # the arguments are only passed for visibility in e.g. the process list '--rmw-implementation', rmw_implementation_identifier, '--ros-domain-id', str(ros_domain_id) ]) if not debug: kwargs['stdout'] = subprocess.DEVNULL kwargs['stderr'] = subprocess.DEVNULL subprocess.Popen(cmd, **kwargs) if wait_until_spawned is None: return True if wait_until_spawned > 0.0: timeout = time.time() + wait_until_spawned else: timeout = None while True: if is_daemon_running(args): return True time.sleep(0.1) if timeout is not None and time.time() >= timeout: return None
def test_create_permission(enclave_dir): assert enclave_dir.joinpath('permissions.xml').is_file() assert enclave_dir.joinpath('permissions.p7s').is_file() tree = lxml.etree.parse(str(enclave_dir.joinpath('permissions.xml'))) # Validate the schema permissions_xsd_path = get_transport_schema('dds', 'permissions.xsd') permissions_xsd = lxml.etree.XMLSchema( lxml.etree.parse(permissions_xsd_path)) permissions_xsd.assertValid(tree) dds = tree.getroot() assert dds.tag == 'dds' permissions = list(dds.iterchildren(tag='permissions')) assert len(permissions) == 1 grants = list(permissions[0].iterchildren(tag='grant')) assert len(grants) == 1 assert grants[0].get('name') == _test_identity allow_rules = list(grants[0].iterchildren(tag='allow_rule')) if rclpy.get_rmw_implementation_identifier( ) in _permission._RMW_WITH_ROS_GRAPH_INFO_TOPIC: assert len(allow_rules) == 2 else: assert len(allow_rules) == 1 publish_rules = list(allow_rules[0].iterchildren(tag='publish')) assert len(publish_rules) == 1 subscribe_rules = list(allow_rules[0].iterchildren(tag='subscribe')) assert len(subscribe_rules) == 1 published_topics_set = list(publish_rules[0].iterchildren(tag='topics')) assert len(published_topics_set) == 1 published_topics = [ c.text for c in published_topics_set[0].iterchildren(tag='topic') ] assert len(published_topics) > 0 subscribed_topics_set = list(subscribe_rules[0].iterchildren(tag='topics')) assert len(subscribed_topics_set) == 1 subscribed_topics = [ c.text for c in subscribed_topics_set[0].iterchildren(tag='topic') ] assert len(subscribed_topics) > 0 # Verify that publication is allowed on chatter, but not subscription assert 'rt/chatter' in published_topics assert 'rt/chatter' not in subscribed_topics
def func_import_each_available_rmw_implementation(rmw_implementation): import rclpy from rclpy.impl.rmw_implementation_tools import get_rmw_implementations from rclpy.impl.rmw_implementation_tools import select_rmw_implementation rmw_implementations = get_rmw_implementations() assert(rmw_implementation in rmw_implementations) select_rmw_implementation(rmw_implementation) rclpy.init([]) set_rmw = rclpy.get_rmw_implementation_identifier() assert set_rmw == rmw_implementation, \ "expected '{0}' but got '{1}'".format( rmw_implementation, set_rmw) return ctypes.c_bool(True)
def spawn_daemon(args, timeout=None, debug=False): """ Spawn daemon node if it's not running. To avoid TOCTOU races, this function instantiates the XMLRPC server (binding the socket in the process) and transfers it to the daemon process through pipes (sending the inheritable socket with it). In a sense, the socket functionally behaves as a mutex. :param args: `DaemonNode` arguments namespace. :param timeout: optional duration, in seconds, to wait until the daemon node is ready. Non-positive durations will result in an indefinite wait. :param debug: if `True`, the daemon process will output to the current `stdout` and `stderr` streams. :return: `True` if the the daemon was spawned, `False` if it was already running. :raises: if it fails to spawn the daemon. """ # Acquire socket by instantiating XMLRPC server. try: server = daemon.make_xmlrpc_server() server.socket.set_inheritable(True) except socket.error as e: if e.errno == errno.EADDRINUSE: # Failed to acquire socket # Daemon already running return False raise # Transfer XMLRPC server to daemon (and the socket with it). try: tags = { 'name': 'ros2-daemon', 'ros_domain_id': get_ros_domain_id(), 'rmw_implementation': rclpy.get_rmw_implementation_identifier()} daemonize( functools.partial(daemon.serve, server), tags=tags, timeout=timeout, debug=debug) finally: server.server_close() return True
def func_select_rmw_implementation_by_environment(rmw_implementation): import rclpy from rclpy.impl.rmw_implementation_tools import get_rmw_implementations os.environ['RCLPY_IMPLEMENTATION'] = rmw_implementation assert('RCLPY_IMPLEMENTATION' in os.environ) rmw_implementations = get_rmw_implementations() assert(os.environ['RCLPY_IMPLEMENTATION'] in rmw_implementations) rclpy.init([]) set_rmw = rclpy.get_rmw_implementation_identifier() assert set_rmw == rmw_implementation, \ "expected '{0}' but got '{1}'".format( rmw_implementation, set_rmw) return ctypes.c_bool(True)
def spawn_daemon(args, wait_until_spawned=None): ros_domain_id = int(os.environ.get('ROS_DOMAIN_ID', 0)) kwargs = {} if platform.system() != 'Windows': cmd = ['_ros2_daemon'] else: # allow closing the shell the daemon was spawned from # while the daemon is still running cmd = [ sys.executable, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'daemon/__init__.py') ] # Process Creation Flag documented in the MSDN DETACHED_PROCESS = 0x00000008 # noqa: N806 kwargs.update(creationflags=DETACHED_PROCESS) # don't keep handle of current working directory in daemon process kwargs.update(cwd=os.environ.get('SYSTEMROOT', None)) subprocess.Popen( cmd + [ # the arguments are only passed for visibility in e.g. the process list '--rmw-implementation', rclpy.get_rmw_implementation_identifier(), '--ros-domain-id', str(ros_domain_id) ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, **kwargs) if wait_until_spawned is None: return True if wait_until_spawned > 0.0: timeout = time.time() + wait_until_spawned else: timeout = None while True: if is_daemon_running(args): return True time.sleep(0.1) if timeout is not None and time.time() >= timeout: return None
def func_import_each_available_rmw_implementation(rmw_implementation): import rclpy from rclpy.impl.rmw_implementation_tools import get_rmw_implementations from rclpy.impl.rmw_implementation_tools import select_rmw_implementation rmw_implementations = get_rmw_implementations() assert(rmw_implementation in rmw_implementations) select_rmw_implementation(rmw_implementation) rclpy.init([]) set_rmw = rclpy.get_rmw_implementation_identifier() assert set_rmw in identifiers_map, \ "expected identifier '{0}' to be in the map '{1}'".format(set_rmw, identifiers_map) set_rmw_equivalent = identifiers_map[set_rmw] assert set_rmw_equivalent == rmw_implementation, \ "expected '{0}' but got '{1}' (aka '{2}')".format( rmw_implementation, set_rmw_equivalent, set_rmw) return ctypes.c_bool(True)
def func_select_rmw_implementation_by_environment(rmw_implementation): import rclpy from rclpy.impl.rmw_implementation_tools import get_rmw_implementations os.environ['RCLPY_IMPLEMENTATION'] = rmw_implementation assert('RCLPY_IMPLEMENTATION' in os.environ) rmw_implementations = get_rmw_implementations() assert(os.environ['RCLPY_IMPLEMENTATION'] in rmw_implementations) rclpy.init([]) set_rmw = rclpy.get_rmw_implementation_identifier() assert set_rmw in identifiers_map, \ "expected identifier '{0}' to be in the map '{1}'".format(set_rmw, identifiers_map) set_rmw_equivalent = identifiers_map[set_rmw] assert set_rmw_equivalent == rmw_implementation, \ "expected '{0}' but got '{1}' (aka '{2}')".format( rmw_implementation, set_rmw_equivalent, set_rmw) return ctypes.c_bool(True)
def main(*, script_name='_ros2_daemon', argv=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '--rmw-implementation', type=str, required=True, help='The RMW implementation name (must match the return value of ' 'rclpy.get_rmw_implementation_identifier())') parser.add_argument( '--ros-domain-id', metavar='N', type=int, required=True, help='The ROS domain id (must match the environment variable ' 'ROS_DOMAIN_ID)') parser.add_argument( '--timeout', metavar='N', type=int, default=2 * 60 * 60, help='Shutdown the daemon after N seconds of inactivity') args = parser.parse_args(args=argv) # the arguments are only passed for visibility in e.g. the process list assert args.rmw_implementation == rclpy.get_rmw_implementation_identifier() assert args.ros_domain_id == int(os.environ.get('ROS_DOMAIN_ID', 0)) addr = ('localhost', get_daemon_port()) NodeArgs = namedtuple('NodeArgs', 'node_name_suffix') node_args = NodeArgs(node_name_suffix='_daemon_%d' % args.ros_domain_id) with DirectNode(node_args) as node: server = LocalXMLRPCServer( addr, logRequests=False, requestHandler=RequestHandler, allow_none=True) try: server.register_introspection_functions() # expose getter functions of node server.register_function( _print_invoked_function_name(node.get_node_names)) server.register_function( _print_invoked_function_name(node.get_topic_names_and_types)) server.register_function( _print_invoked_function_name(node.get_service_names_and_types)) shutdown = False # shutdown the daemon in case of a timeout def timeout_handler(): nonlocal shutdown print('Shutdown due to timeout') shutdown = True server.handle_timeout = timeout_handler server.timeout = args.timeout # function to shutdown daemon remotely def shutdown_handler(): nonlocal shutdown print('Remote shutdown requested') shutdown = True server.register_function(shutdown_handler, 'system.shutdown') print('Serving XML-RPC on %s:%d/ros2cli/' % (addr[0], addr[1])) try: while not shutdown: server.handle_request() except KeyboardInterrupt: pass finally: server.server_close()
class RequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = ('/%s/' % rclpy.get_rmw_implementation_identifier(), )