def openLog(cls, nodename, host, user=None, only_screen=False): ''' Opens the log file associated with the given node in a new terminal. :param str nodename: the name of the node (with name space) :param str host: the host name or ip where the log file are :return: True, if a log file was found :rtype: bool :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' rospy.loginfo("show log for '%s' on '%s'", utf8(nodename), utf8(host)) title_opt = 'LOG %s on %s' % (nodename, host) if nm.is_local(host): found = False screenLog = screen.get_logfile(node=nodename) if os.path.isfile(screenLog): cmd = nm.settings().terminal_cmd( [nm.settings().log_viewer, screenLog], title_opt) rospy.loginfo("open log: %s", cmd) SupervisedPopen(shlex.split(cmd), object_id="Open log", description="Open log for '%s' on '%s'" % (utf8(nodename), utf8(host))) found = True # open roslog file roslog = screen.get_ros_logfile(nodename) if os.path.isfile(roslog) and not only_screen: title_opt = title_opt.replace('LOG', 'ROSLOG') cmd = nm.settings().terminal_cmd( [nm.settings().log_viewer, roslog], title_opt) rospy.loginfo("open ROS log: %s", cmd) SupervisedPopen(shlex.split(cmd), object_id="Open log", description="Open log for '%s' on '%s'" % (utf8(nodename), utf8(host))) found = True return found else: _ps = nm.ssh().ssh_x11_exec(host, [ nm.settings().start_remote_script, '--show_screen_log', nodename ], title_opt, user) if not only_screen: _ps = nm.ssh().ssh_x11_exec(host, [ nm.settings().start_remote_script, '--show_ros_log', nodename ], title_opt.replace('LOG', 'ROSLOG'), user) return False
def _killall_roscore_wo(self, host, auto_pw_request=False, user=None, pw=None): rospy.loginfo("killall roscore on %s", host) cmd = ['killall', 'roscore'] if nm.is_local(host): SupervisedPopen(cmd, object_id="killall roscore", description="killall roscore") else: # kill on a remote machine _, stdout, stderr, ok = nm.ssh().ssh_exec(host, cmd, user, pw, False, close_stdin=True) if ok: output = stdout.read() error = stderr.read() stdout.close() stderr.close() if error: rospy.logwarn("ERROR while killall roscore on %s: %s" % (host, error)) raise StartException('The host "%s" reports:\n%s' % (host, error)) if output: rospy.logdebug("STDOUT while killall roscore on %s: %s" % (host, output))
def _kill_wo(self, host, pid, auto_pw_request=False, user=None, pw=None): rospy.loginfo("kill %s on %s", utf8(pid), host) if nm.is_local(host): os.kill(pid, signal.SIGKILL) rospy.loginfo("kill: %s", utf8(pid)) else: # kill on a remote machine cmd = ['kill -9', str(pid)] _, stdout, stderr, ok = nm.ssh().ssh_exec(host, cmd, user, pw, False, close_stdin=True) if ok: output = stdout.read() error = stderr.read() stdout.close() stderr.close() if error: rospy.logwarn("ERROR while kill %s: %s", utf8(pid), error) raise StartException( utf8(''.join( ['The host "', host, '" reports:\n', error]))) if output: rospy.logdebug("STDOUT while kill %s on %s: %s", utf8(pid), host, output)
def open_screen_terminal(cls, masteruri, screen_name, nodename, use_log_widget=False, user=None): ''' Open the screen output in a new terminal. :param str masteruri: the masteruri where the screen is running. :param str screen_name: the name of the screen to show :param str nodename: the name of the node is used for the title of the terminal :raise Exception: on errors while resolving host :see: L{fkie_node_manager.is_local()} ''' # create a title of the terminal if use_log_widget: nm._MAIN_FORM.open_screen_dock(masteruri, screen_name, nodename, user) return host = get_hostname(masteruri) title_opt = 'SCREEN %s on %s' % (nodename, host) if nm.is_local(host): cmd = nm.settings().terminal_cmd( [screen.SCREEN, '-x', screen_name], title_opt) rospy.loginfo("Open screen terminal: %s", cmd) SupervisedPopen(shlex.split(cmd), object_id=title_opt, description="Open screen terminal: %s" % title_opt) else: rospy.loginfo("Open remote screen terminal for %s to %s" % (nodename, host)) _ps = nm.ssh().ssh_x11_exec(host, [screen.SCREEN, '-x', screen_name], title_opt, user)
def _connect_ssh(self, host, nodename, user=None, pw=None): try: if user is not None: self.infoLabel.setText('connecting to %s@%s' % (user, host)) else: self.infoLabel.setText('connecting to %s' % host) ok = False self.ssh_input_file, self.ssh_output_file, self.ssh_error_file, ok = nm.ssh( ).ssh_exec(host, [ nm.settings().start_remote_script, '--tail_screen_log', nodename ], user, pw, auto_pw_request=False, get_pty=True) if ok: thread = threading.Thread(target=self._read_ssh_output, args=((self.ssh_output_file, ))) thread.setDaemon(True) thread.start() thread = threading.Thread(target=self._read_ssh_error, args=((self.ssh_error_file, ))) thread.setDaemon(True) thread.start() elif self.ssh_output_file: self.ssh_output_file.close() self.ssh_error_file.close() except nm.AuthenticationRequest as e: self.auth_signal.emit(host, nodename, user) except Exception as e: self.error_signal.emit('%s\n' % e)
def _bc_resolve_abs_paths(cls, value, host, auto_pw_request, user, pw): ''' Replaces the local absolute path by remote absolute path. Only valid ROS package paths are resolved. :return: value, is absolute path, remote package found (ignore it on local host or if is not absolute path!), package name (if absolute path and remote package NOT found) ''' if isstring(value) and value.startswith('/') and (os.path.isfile(value) or os.path.isdir(value)): if nm.is_local(host): return value, True, True, '' else: path = os.path.dirname(value) if os.path.isfile(value) else value package, package_path = package_name(path) if package: _, stdout, _, ok = nm.ssh().ssh_exec(host, ['rospack', 'find', package], user, pw, auto_pw_request, close_stdin=True, close_stderr=True) output = stdout.read() stdout.close() if ok: if output: value.replace(package_path, output) return value.replace(package_path, output.strip()), True, True, package else: # package on remote host not found! # TODO add error message # error = stderr.read() pass return value, True, False, '' else: return value, False, False, ''
def ntpdate(cls, host, cmd, user=None, pw=None): ''' Opens the log file associated with the given node in a new terminal. :param str host: the host name or ip where the log file are :param str cmd: command to set the time :return: True, if a log file was found :rtype: bool :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' mesg = "synchronize time on '%s' using '%s'" % (utf8(host), cmd) rospy.loginfo(mesg) title_opt = "ntpdate on %s" % str(host) # '%s on %s' % (cmd, host) if nm.is_local(host): cmd = nm.settings().terminal_cmd([cmd], title_opt, noclose=True) rospy.loginfo("EXEC: %s" % cmd) _ps = SupervisedPopen(shlex.split(cmd), object_id=cmd, description=mesg) else: _ps = nm.ssh().ssh_x11_exec(host, [ cmd, ';echo "";echo "this terminal will be closed in 10 sec...";sleep 10' ], title_opt, user) return False
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 _poweroff_wo(self, host, auto_pw_request=False, user=None, pw=None): if nm.is_local(host): rospy.logwarn("shutdown localhost localhost!") cmd = nm.settings().terminal_cmd(['sudo poweroff'], "poweroff") SupervisedPopen(shlex.split(cmd), object_id="poweroff", description="poweroff") else: rospy.loginfo("poweroff %s", host) # kill on a remote machine cmd = ['sudo poweroff'] _ = nm.ssh().ssh_x11_exec(host, cmd, 'Shutdown %s' % host, user)
def _on_display_anchorClicked(self, url, user=None, pw=None): try: ok = False if self.show_only_rate: self.ssh_input_file, self.ssh_output_file, self.ssh_error_file, ok = nm.ssh( ).ssh_exec(url.host(), ['rostopic hz %s' % (self.topic)], user, pw, auto_pw_request=True, get_pty=True) self.statusLabel.setText('connected to %s over SSH' % url.host()) else: nostr = '--nostr' if not self.showStringsCheckBox.isChecked( ) else '' noarr = '--noarr' if not self.showArraysCheckBox.isChecked( ) else '' self.ssh_input_file, self.ssh_output_file, self.ssh_error_file, ok = nm.ssh( ).ssh_exec( url.host(), ['rostopic echo %s %s %s' % (nostr, noarr, self.topic)], user, pw, auto_pw_request=True, get_pty=True) if ok: self.display.clear() target = self._read_output_hz if self.show_only_rate else self._read_output thread = threading.Thread(target=target, args=((self.ssh_output_file, ))) thread.setDaemon(True) thread.start() thread = threading.Thread(target=self._read_error, args=((self.ssh_error_file, ))) thread.setDaemon(True) thread.start() elif self.ssh_output_file: self.ssh_output_file.close() self.ssh_error_file.close() except Exception as e: self._append_error_text('%s\n' % e)
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 _rosclean_wo(self, grpc_uri, auto_pw_request=False, user=None, pw=None): try: nm.nmd().screen.rosclean(grpc_uri) except Exception as err: host = get_hostname(grpc_uri) if nm.is_local(host): rospy.loginfo("rosclean purge on localhost!") cmd = nm.settings().terminal_cmd(['rosclean purge -y'], "rosclean") SupervisedPopen(shlex.split(cmd), object_id="rosclean", description="rosclean") else: rospy.logwarn("use SSH to run 'rosclean' because of error: %s" % utf8(err)) # kill on a remote machine cmd = ['rosclean purge -y'] _ = nm.ssh().ssh_x11_exec(host, cmd, 'rosclean purge on %s' % host, user)
def _bc_get_active_screens(cls, host, nodename='', auto_pw_request=True, user=None, pwd=None): ''' Returns the list with all compatible screen names. If the session is set to an empty string all screens will be returned. :param str host: the host name or IP to search for the screen session. :param str nodename: the name of the node :return: dictionary of screen name and corresponding ROS node name :rtype: {str: str} :raise Exception: on errors while resolving host :see: fkie_node_manager.is_local() ''' output = None result = {} if nm.is_local(host): ps = SupervisedPopen(shlex.split('%s -ls' % screen.SCREEN), stdout=subprocess.PIPE) output = ps.stdout.read() ps.stdout.close() else: _, stdout, _, _ = nm.ssh().ssh_exec(host, [screen.SCREEN, ' -ls'], user, pwd, auto_pw_request, close_stdin=True, close_stderr=True) output = stdout.read() stdout.close() if output: splits = output.split() session = utf8(nodename).replace( '/', '_') if nodename is not None else '' for i in splits: sname = i.replace('__', '_') if sname.count('.') > 0 and sname.endswith( session) and sname.find('._') >= 0: result[i] = nodename return result
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 on_request_pw(self, host, nodename, user): res, user, pw = nm.ssh()._requestPW(user, host) if res: self._connect_ssh(host, nodename, user, 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 _on_request_interact(self, ident, descr, req): ''' If the interaction of the user is needed a message dialog must be exceuted in the main Qt thread. The requests are done by different request exceptinos. These are handled by this method. ''' if isinstance(req.request, nm.AuthenticationRequest): res, user, pw = nm.ssh()._requestPW(req.request.user, req.request.host) if not res: self._on_progress_canceled() return req.args = req.args + (user, pw) pt = ProgressThread(ident, descr, req.method, (req.args)) pt.finished_signal.connect(self._progress_thread_finished) pt.error_signal.connect(self._progress_thread_error) pt.request_interact_signal.connect(self._on_request_interact) pt.start() elif isinstance(req.request, nm.ScreenSelectionRequest): from fkie_node_manager.select_dialog import SelectDialog items, _ = SelectDialog.getValue('Show screen', '', req.request.choices.keys(), False, store_geometry='screen_select') if not items: self._progress_thread_finished(ident) return res = [req.request.choices[i] for i in items] pt = ProgressThread(ident, descr, req.method, (req.args + (res, ))) pt.finished_signal.connect(self._progress_thread_finished) pt.error_signal.connect(self._progress_thread_error) pt.request_interact_signal.connect(self._on_request_interact) pt.start() elif isinstance(req.request, nm.BinarySelectionRequest): from fkie_node_manager.select_dialog import SelectDialog items, _ = SelectDialog.getValue('Multiple executables', '', req.request.choices, True, store_geometry='binary_select') if not items: self._progress_thread_finished(ident) return res = items[0] req.args = req.args + (res, ) pt = ProgressThread(ident, descr, req.method, (req.args)) pt.finished_signal.connect(self._progress_thread_finished) pt.error_signal.connect(self._progress_thread_error) pt.request_interact_signal.connect(self._on_request_interact) pt.start() elif isinstance(req.request, nm.LaunchArgsSelectionRequest): from fkie_node_manager.parameter_dialog import ParameterDialog input_dia = ParameterDialog(req.request.args_dict, store_geometry="launch_dialog") input_dia.setFilterVisible(False) input_dia.setWindowTitle('Enter the argv for %s' % req.request.launchfile) if input_dia.exec_(): params = input_dia.getKeywords() argv = [] for prm, val in params.items(): if val: argv.append('%s:=%s' % (prm, val)) res = argv pt = ProgressThread(ident, descr, req.method, (req.args + (params, ))) pt.finished_signal.connect(self._progress_thread_finished) pt.error_signal.connect(self._progress_thread_error) pt.request_interact_signal.connect(self._on_request_interact) pt.start() else: self._progress_thread_finished(ident) return elif isinstance(req.request, nm.NoScreenOpenLogRequest): self.no_screen_error_signal.emit(req.request.node, req.request.host) self._progress_thread_finished(ident)
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 })