def delete_log(cls, nodename, grpc_uri, auto_pw_request=False, user=None, pw=None): ''' Deletes the log file associated with the given node. :param str nodename: the name of the node (with name space) :param str grpc_uri: uri of the node manager daemon where to delete log :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' try: nm.nmd().screen.delete_log(grpc_uri, [nodename]) except Exception as err: rospy.logwarn("delete log using SSH because of error: %s" % utf8(err)) host = get_hostname(grpc_uri) if nm.is_local(host): screenLog = screen.get_logfile(node=nodename) pidFile = screen.get_pidfile(node=nodename) roslog = screen.get_ros_logfile(nodename) if os.path.isfile(screenLog): os.remove(screenLog) if os.path.isfile(pidFile): os.remove(pidFile) if os.path.isfile(roslog): os.remove(roslog) else: try: # output ignored: output, error, ok _, stdout, _, ok = nm.ssh().ssh_exec(host, [nm.settings().start_remote_script, '--delete_logs', nodename], user, pw, auto_pw_request, close_stdin=True, close_stdout=False, close_stderr=True) if ok: stdout.readlines() stdout.close() except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, cls.delete_log, {'nodename': nodename, 'grpc_uri': host, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
def kill_screens(cls, node, grpc_url, auto_ok_request=True, user=None, pw=None): ''' Searches for the screen associated with the given node and kill this screens. :param str node: the name of the node those screen output to kill :param str grpc_url: the url of node manager daemon where the screen is running ''' if node is None or len(node) == 0: return False try: # get the available screens screens = nm.nmd().screen.get_screens(grpc_url, node) if screens: do_kill = True if auto_ok_request: from fkie_node_manager.detailed_msg_box import MessageBox result = MessageBox.question( None, "Kill SCREENs?", '\n'.join(list(screens.keys())), buttons=MessageBox.Ok | MessageBox.Cancel) if result == MessageBox.Ok: do_kill = True if do_kill: host = get_hostname(grpc_url) for sname, _nname in screens.items(): pid, _, _ = sname.partition('.') if pid: try: nm.nmd().monitor.kill_process( int(pid), grpc_url) # nm.starter()._kill_wo(host, int(pid), auto_ok_request, user, pw) except Exception: import traceback rospy.logwarn( "Error while kill screen (PID: %s) on host '%s': %s", utf8(pid), utf8(host), traceback.format_exc(1)) nm.nmd().screen.wipe_screens(grpc_url) # if nm.is_local(host): # SupervisedPopen([screen.SCREEN, '-wipe'], object_id='screen -wipe', description="screen: clean up the socket with -wipe") # else: # nm.ssh().ssh_exec(host, [screen.SCREEN, '-wipe'], close_stdin=True, close_stdout=True, close_stderr=True) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.kill_screens, { 'node': node, 'grpc_url': grpc_url, 'auto_ok_request': auto_ok_request, 'user': user, 'pw': pw })
def rosclean(self, grpc_uri, auto_pw_request=False, user=None, pw=None): ''' rosclean purge on given host. :param str grpc_uri: the address of the node manager daemon where rosclean is called. :raise StartException: on error :raise Exception: on errors while resolving host :see: L{fkie_node_manager.is_local()} ''' try: self._rosclean_wo(grpc_uri, auto_pw_request, user, pw) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, self.rosclean, {'grpc_uri': grpc_uri, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
def poweroff(self, host, auto_pw_request=False, user=None, pw=None): ''' poweroff given host. :param str host: the name or address of the host, where the process must be killed. :raise StartException: on error :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' try: self._poweroff_wo(host, auto_pw_request, user, pw) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, self.poweroff, {'host': host, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
def killall_roscore(self, host, auto_pw_request=False, user=None, pw=None): ''' Kills all roscore processes on given host. :param str host: the name or address of the host, where the process must be killed. :raise StartException: on error :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' try: self._killall_roscore_wo(host, auto_pw_request, user, pw) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, self.killall_roscore, (host, auto_pw_request))
def get_log_path(cls, host, nodes=[], auto_pw_request=False, user=None, pw=None): if nm.is_local(host): if len(nodes) == 1: return screen.get_logfile(node=nodes[0]) else: return screen.LOG_PATH else: request = '[]' if len(nodes) != 1 else nodes[0] try: socket.setdefaulttimeout(3) _, stdout, _, ok = nm.ssh().ssh_exec(host, [ nm.settings().start_remote_script, '--ros_log_path', request ], user, pw, auto_pw_request, close_stdin=True, close_stderr=True) if ok: output = stdout.read() stdout.close() return output.strip() else: raise StartException( utf8(''.join(['Get log path from "', host, '" failed']))) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.get_log_path, { 'host': host, 'nodes': nodes, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw }) finally: socket.setdefaulttimeout(None)
def transfer_files(cls, host, path, auto_pw_request=False, user=None, pw=None): ''' Copies the given file to the remote host. Uses caching of remote paths. ''' # get package of the file if nm.is_local(host): # it's local -> no copy needed return (pkg_name, pkg_path) = package_name(os.path.dirname(path)) if pkg_name is not None: # get the subpath of the file subfile_path = path.replace(pkg_path, '') # get the path of the package on the remote machine try: output = '' error = '' ok = True if host in CACHED_PKG_PATH and pkg_name in CACHED_PKG_PATH[host]: output = CACHED_PKG_PATH[host][pkg_name] else: if host not in CACHED_PKG_PATH: CACHED_PKG_PATH[host] = dict() _, stdout, stderr, ok = nm.ssh().ssh_exec(host, [nm.settings().start_remote_script, '--package', pkg_name], user, pw, auto_pw_request, close_stdin=True) output = stdout.read() error = stderr.read() stdout.close() stderr.close() if ok: if error: rospy.logwarn("ERROR while transfer %s to %s: %s", path, host, error) raise StartException(utf8(''.join(['The host "', host, '" reports:\n', error]))) if output: CACHED_PKG_PATH[host][pkg_name] = output nm.ssh().transfer(host, path, os.path.join(output.strip(), subfile_path.strip(os.sep)), user) else: raise StartException("Remote host no returned any answer. Is there the new version of node_manager installed?") else: raise StartException("Can't get path from remote host. Is there the new version of node_manager installed?") except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, cls.transfer_files, {'host': host, 'path': path, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw})
def bc_run_node(cls, name, grpc_path='grpc://localhost:12321', masteruri='', reload_global_param=False, loglevel='', logformat='', auto_pw_request=False, user=None, pw=None): ''' Start the node with given name from the given configuration. :param runcfg: the configuration containing the start parameter :type runcfg: AdvRunCfg :raise StartException: if the screen is not available on host. :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' startcfg = nm.nmd().launch.get_start_cfg( name, grpc_path, masteruri, reload_global_param=reload_global_param, loglevel=loglevel, logformat=logformat) new_env = dict(startcfg.env) # set logging options if startcfg.namespace: new_env['ROS_NAMESPACE'] = startcfg.namespace # set logging if startcfg.logformat: new_env['ROSCONSOLE_FORMAT'] = '%s' % startcfg.logformat # if startcfg.loglevel: # new_env['ROSCONSOLE_CONFIG_FILE'] = launcher._rosconsole_cfg_file(startcfg.package, startcfg.loglevel) args = [] # set name and namespace of the node if startcfg.name: args.append("__name:=%s" % startcfg.name) if startcfg.namespace: args.append("__ns:=%s" % startcfg.namespace) # add remap arguments for key, val in startcfg.remaps.items(): args.append("%s:=%s" % (key, val)) # handle respawn if startcfg.respawn: if startcfg.respawn_delay > 0: new_env['RESPAWN_DELAY'] = '%d' % startcfg.respawn_delay respawn_params = launcher._get_respawn_params( startcfg.fullname, startcfg.params) if respawn_params['max'] > 0: new_env['RESPAWN_MAX'] = '%d' % respawn_params['max'] if respawn_params['min_runtime'] > 0: new_env['RESPAWN_MIN_RUNTIME'] = '%d' % respawn_params[ 'min_runtime'] if startcfg.cwd: cwd = get_cwd(startcfg.cwd, startcfg.binary_path) if cwd: args.append('__cwd:=%s' % cwd) # check for masteruri masteruri = startcfg.masteruri on_hostname = startcfg.hostname if masteruri is None: masteruri = masteruri_from_ros() if masteruri is not None: new_env['ROS_MASTER_URI'] = masteruri if 'ROS_HOSTNAME' in os.environ: # set only ROS_HOSTNAME if node manager have also one ros_hostname = nmdhost.get_ros_hostname(masteruri, on_hostname) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname # load params to ROS master launcher._load_parameters(masteruri, startcfg.params, startcfg.clear_params) abs_paths = list() # tuples of (parameter name, old value, new value) not_found_packages = list() # package names # # set the global parameter # if runcfg.masteruri is not None and runcfg.masteruri not in runcfg.roslaunch_config.global_param_done: # global_node_names = cls.getGlobalParams(runcfg.roslaunch_config.Roscfg) # rospy.loginfo("Register global parameter:\n %s", '\n '.join("%s%s" % (utf8(v)[:80], '...' if len(utf8(v)) > 80 else'') for v in global_node_names.values())) # abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(runcfg.masteruri, global_node_names, [], runcfg.user, runcfg.pw, runcfg.auto_pw_request) # runcfg.roslaunch_config.global_param_done.append(runcfg.masteruri) # # # add params # if runcfg.masteruri is not None: # nodens = ''.join([n.namespace, n.name, rospy.names.SEP]) # params = dict() # for param, value in runcfg.roslaunch_config.Roscfg.params.items(): # if param.startswith(nodens): # params[param] = value # clear_params = [] # for cparam in runcfg.roslaunch_config.Roscfg.clear_params: # if cparam.startswith(nodens): # clear_params.append(cparam) # rospy.loginfo("Delete parameter:\n %s", '\n '.join(clear_params)) # rospy.loginfo("Register parameter:\n %s", '\n '.join("%s%s" % (utf8(v)[:80], '...' if len(utf8(v)) > 80 else'') for v in params.values())) # abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(runcfg.masteruri, params, clear_params, runcfg.user, runcfg.pw, runcfg.auto_pw_request) if not nm.is_local(on_hostname, wait=True): # start remote if not startcfg.package: raise StartException( "Can't run remote without a valid package name!") # setup environment env_command = '' if new_env: try: for k, v in new_env.items(): v_value, is_abs_path, found, package = cls._bc_resolve_abs_paths( v, on_hostname, auto_pw_request, user, pw) new_env[k] = v_value if is_abs_path: abs_paths.append(('ENV', "%s=%s" % (k, v), "%s=%s" % (k, v_value))) if not found and package: not_found_packages.append(package) env_command = "env " + ' '.join( ["%s=\'%s\'" % (k, v) for (k, v) in new_env.items()]) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.bc_run_node, { 'name': name, 'grpc_path': grpc_path, 'masteruri': masteruri, 'reload_global_param': reload_global_param, 'loglevel': loglevel, 'logformat': logformat, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw }) startcmd = [ env_command, nm.settings().start_remote_script, '--package', utf8(startcfg.package), '--node_type', utf8(startcfg.binary), '--node_name', utf8(startcfg.fullname), '--node_respawn true' if startcfg.respawn else '' ] if startcfg.masteruri is not None: startcmd.append('--masteruri') startcmd.append(startcfg.masteruri) if startcfg.prefix: startcmd[len(startcmd):] = ['--prefix', startcfg.prefix] if startcfg.loglevel: startcmd.append('--loglevel') startcmd.append(startcfg.loglevel) # rename the absolute paths in the args of the node node_args = [] error = '' output = '' try: for a in startcfg.args: a_value, is_abs_path, found, package = cls._bc_resolve_abs_paths( a, on_hostname, auto_pw_request, user, pw) node_args.append(a_value) if is_abs_path: abs_paths.append(('ARGS', a, a_value)) if not found and package: not_found_packages.append(package) startcmd[len(startcmd):] = node_args startcmd[len(startcmd):] = args rospy.loginfo("Run remote on %s: %s", on_hostname, utf8(' '.join(startcmd))) _, stdout, stderr, ok = nm.ssh().ssh_exec(on_hostname, startcmd, user, pw, auto_pw_request, close_stdin=True) output = stdout.read() error = stderr.read() stdout.close() stderr.close() except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.bc_run_node, { 'name': name, 'grpc_path': grpc_path, 'masteruri': masteruri, 'reload_global_param': reload_global_param, 'loglevel': loglevel, 'logformat': logformat, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw }) if ok: if error: rospy.logwarn("ERROR while start '%s': %s", startcfg.fullname, error) raise StartException( utf8(''.join( ['The host "', on_hostname, '" reports:\n', error]))) if output: rospy.logdebug("STDOUT while start '%s': %s", startcfg.fullname, output) # inform about absolute paths in parameter value if len(abs_paths) > 0: rospy.loginfo( "Absolute paths found while start:\n%s", utf8('\n'.join([ ''.join([p, '\n OLD: ', ov, '\n NEW: ', nv]) for p, ov, nv in abs_paths ]))) if len(not_found_packages) > 0: packages = '\n'.join(not_found_packages) raise StartException( utf8('\n'.join([ 'Some absolute paths are not renamed because following packages are not found on remote host:', packages ])))
def runNodeWithoutConfig(cls, host, package, binary, name, args=[], masteruri=None, use_nmd=True, auto_pw_request=False, user=None, pw=None, path=''): ''' Start a node with using a launch configuration. :param str hosturi: the host or ip to run the node :param str package: the ROS package containing the binary :param str binary: the binary of the node to execute :param str name: the ROS name of the node (with name space) :param args: the list with arguments passed to the binary :type args: [str] :param bool use_nmd: start the node using node manager daemon :param bool auto_pw_request: opens question dialog directly, use True only if the method is called from the main GUI thread :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' # create the name with namespace args2 = list(args) fullname = roslib.names.ns_join(roslib.names.SEP, name) namespace = '' for a in args: if a.startswith('__ns:='): namespace = a.replace('__ns:=', '') fullname = roslib.names.ns_join(namespace, name) args2.append(''.join(['__name:=', name])) # run on local host if nm.is_local(host, wait=True): if not use_nmd: if path: cmd = [path] else: try: cmd = roslib.packages.find_node(package, binary) except roslib.packages.ROSPkgException as e: # multiple nodes, invalid package raise StartException(utf8(e)) # handle different result types str or array of string if isstring(cmd): cmd = [cmd] cmd_type = '' if cmd is None or len(cmd) == 0: raise StartException('%s in package [%s] not found!' % (binary, package)) # compatibility for python scripts installed with catkin_install_python() # avoid ask for select a binary cmd = cls._remove_src_binary(cmd) if len(cmd) > 1: # Open selection for executables err = 'Multiple executables with same name in package [%s] found' % package bsel = nm.BinarySelectionRequest(cmd, err) raise nm.InteractionNeededError( bsel, cls.runNodeWithoutConfig, { 'host': host, 'package': package, 'binary': binary, 'name': name, 'args': args, 'masteruri': masteruri, 'use_nmd': use_nmd, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw, 'path': path }) else: cmd_type = cmd[0] new_env = {} # dict(os.environ) if namespace: new_env['ROS_NAMESPACE'] = namespace if masteruri is not None: cls._prepareROSMaster(masteruri) new_env['ROS_MASTER_URI'] = masteruri if 'ROS_HOSTNAME' in os.environ: # set ROS_HOSTNAME only if node_manager has also one ros_hostname = nmdhost.get_ros_hostname(masteruri, host) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname if use_nmd: nm.nmd().launch.start_standalone_node(nmdurl.nmduri(), package, binary, name, namespace, args, new_env, masteruri, host) else: local_env = dict(os.environ) local_env.update(new_env) cmd_str = utf8(' '.join([ screen.get_cmd(fullname, local_env), cmd_type, ' '.join(args2) ])) rospy.loginfo("Run without config: %s", fullname if use_nmd else cmd_str) SupervisedPopen(shlex.split(cmd_str), env=local_env, object_id="Run without config", description="Run without config [%s]%s" % (utf8(package), utf8(binary))) else: # run on a remote machine startcmd = [ nm.settings().start_remote_script, '--package', utf8(package), '--node_type', utf8(binary), '--node_name', utf8(fullname) ] startcmd[len(startcmd):] = args2 if masteruri is not None: startcmd.append('--masteruri') startcmd.append(masteruri) rospy.loginfo("Run remote on %s: %s", host, ' '.join(startcmd)) try: _, stdout, stderr, ok = nm.ssh().ssh_exec(host, startcmd, user, pw, auto_pw_request, close_stdin=True) if ok: output = stdout.read() error = stderr.read() stdout.close() stderr.close() if error: rospy.logwarn("ERROR while start '%s': %s", name, error) raise StartException(''.join( ['The host "', host, '" reports:\n', error])) if output: if output.find("dn't") != -1: rospy.logwarn("Warning while start '%s': %s", name, output) else: rospy.loginfo("STDOUT while start '%s': %s", name, output) else: if error: rospy.logwarn("ERROR while start '%s': %s", name, error) raise StartException(''.join( ['The host "', host, '" reports:\n', error])) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.runNodeWithoutConfig, { 'host': host, 'package': package, 'binary': binary, 'name': name, 'args': args, 'masteruri': masteruri, 'use_nmd': use_nmd, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw, 'path': path })
def open_screen(cls, node, grpc_url, auto_item_request=False, use_log_widget=False, user=None, pw=None, items=[], use_nmd=True): ''' Searches for the screen associated with the given node and open the screen output in a new terminal. :param str node: the name of the node those screen output to show :param str grpc_url: the url of node manager daemon where the screen is running :raise Exception: on errors while resolving host :see: L{open_screen_terminal()} ''' if node is None or len(node) == 0: return False try: host = get_hostname(grpc_url) try: muri = url.masteruri(grpc_url) except ValueError: muri = host if items: for item in items: # open the selected screen cls.open_screen_terminal(muri, item, node, use_log_widget, user) else: # get the available screens screens = {} try: if use_nmd: screens = nm.nmd().screen.get_screens(grpc_url, node) else: screens = cls._bc_get_active_screens(host, node, False, user=user, pwd=pw) except grpc.RpcError as e: rospy.logwarn( "can not connect to node manager daemon, detect screens using ssh..." ) screens = cls._bc_get_active_screens(host, node, False, user=user, pwd=pw) if len(screens) == 1: cls.open_screen_terminal(muri, list(screens.keys())[0], node, use_log_widget, user) else: # create a list to let the user make a choice, which screen must be open choices = {} for sname, _nname in screens.items(): pid, session_name = screen.split_session_name(sname) choices['%s [%d]' % (session_name, pid)] = sname # Open selection if len(choices) > 0: if len(choices) == 1: cls.open_screen_terminal(muri, choices[0], node, use_log_widget=False, user=user) elif auto_item_request: from select_dialog import SelectDialog items, _ = SelectDialog.getValue( 'Show screen', '', list(choices.keys()), False, store_geometry='show_screens') for item in items: # open the selected screen cls.open_screen_terminal(muri, choices[item], node, use_log_widget=False, user=user) else: raise ScreenSelectionRequest( choices, 'Show screen') else: if use_log_widget: nm._MAIN_FORM.open_screen_dock( muri, '', node, user) raise nm.InteractionNeededError( NoScreenOpenLogRequest(node, host), nm.starter().openLog, (node, host, user)) return len(screens) > 0 except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.open_screen, (node, grpc_url, auto_item_request, use_log_widget)) except ScreenSelectionRequest as e: # set use_log_widget to False on multiple screens for same node raise nm.InteractionNeededError( e, cls.open_screen, (node, grpc_url, auto_item_request, False, user, pw))