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 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 _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 _connect(self, masteruri, screen_name, nodename, user=None): self._masteruri = masteruri if self.qfile is not None and self.qfile.isOpen(): self.qfile.close() self.clear_signal.emit() host = get_hostname(masteruri) if nm.is_local(host): self._nodename = nodename if screen_name: screen_log = screen.get_logfile(node=nodename) else: screen_log = screen.get_ros_logfile(node=nodename) self.qfile = QFile(screen_log) self.setWindowTitle(nodename) if self.qfile.open(QIODevice.ReadOnly): self._first_fill = True self.qfile.seek(self.qfile.size() - 1) # self.lread() self._info = "END" self.thread = threading.Thread(target=self._read_log, kwargs={"filename": screen_log}) self.thread.setDaemon(True) self.thread.start() else: self._valid = False else: self._connect_ssh(host, nodename, user) self.logger_handler = LoggerHandler( nodename, masteruri=masteruri, layout=self.scrollAreaWidgetContents.layout()) self.logger_handler.update() 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 open_terminal(self, host): if nm.is_local(host): cmd = nm.settings().terminal_cmd(['cd'], '') SupervisedPopen(shlex.split(cmd), object_id="Start local terminal", shell=True) else: cmd = nm.settings().terminal_cmd(["ssh -XC %s@%s" % (nm.settings().host_user(host), host)], '', noclose=True) SupervisedPopen(shlex.split(cmd), object_id="Start Terminal on %s" % host)
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 _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 _prepareROSMaster(cls, masteruri): if masteruri is None: masteruri = masteruri_from_ros() # start roscore, if needed try: if not os.path.isdir(screen.LOG_PATH): os.makedirs(screen.LOG_PATH) socket.setdefaulttimeout(3) master = xmlrpcclient.ServerProxy(masteruri) master.getUri(rospy.get_name()) # restart ROSCORE on different masteruri?, not now... # master_uri = master.getUri(rospy.get_name()) # if masteruri != master_uri[2]: # # kill the local roscore... # raise except Exception: # run a roscore master_host = get_hostname(masteruri) if nm.is_local(master_host, True): master_port = get_port(masteruri) new_env = dict(os.environ) new_env['ROS_MASTER_URI'] = masteruri ros_hostname = nmdhost.get_ros_hostname(masteruri) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname cmd_args = '%s roscore --port %d' % (screen.get_cmd('/roscore--%d' % master_port), master_port) for n in [1, 2, 3, 4]: try: if n == 1: print("Launch ROS Master in screen ... %s" % (cmd_args)) SupervisedPopen(shlex.split(cmd_args), env=new_env, object_id="ROSCORE", description="Start roscore") elif n == 2: print("ROS Master takes too long for start, wait for next 10 sec ...") elif n == 3: print("A really slow start, wait for last 10 sec ...") # wait for roscore to avoid connection problems while init_node result = -1 count = 1 while result == -1 and count < 11: try: master = xmlrpcclient.ServerProxy(masteruri) result, _, _ = master.getUri(rospy.get_name()) # _:=uri, msg return except Exception: time.sleep(1) count += 1 if n == 4 and count >= 11: raise StartException('Cannot connect to ROS-Master: %s\n--> please run "roscore" manually!' % utf8(masteruri)) except Exception as e: raise Exception("Error while call '%s': %s" % (cmd_args, utf8(e))) else: raise Exception("ROS master '%s' is not reachable" % masteruri) finally: socket.setdefaulttimeout(None)
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 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 __gt__(self, item): if isstring(item): local = False try: local = nm.is_local(get_hostname(nm.nameres().masteruri(item))) except Exception: pass if self.local and not local: # local hosts are at the top return False return self.master.name.lower() > item.lower() elif not (item is None): if self.local and not item.local: # local hosts are at the top return False return self.master.name.lower() > item.master.name.lower() return False
def __gt__(self, item): if isinstance(item, str) or isinstance(item, unicode): local = False try: local = nm.is_local(item) except Exception: pass if self.local and not local: # local hosts are at the top return False return self.master.name.lower() > item.lower() elif not (item is None): if self.local and not item.local: # local hosts are at the top return False return self.master.name.lower() > item.master.name.lower() return False
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 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 updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: U{fkie_master_discovery.msg.ROSMaster<http://docs.ros.org/api/fkie_multimaster_msgs/html/msg/ROSMaster.html>} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) try: del self.pyqt_workaround[masterItem.master.name] except Exception: pass break # update or add a the item root = self.invisibleRootItem() doAddItem = True is_local = nm.is_local(get_hostname(master.uri)) for index in range(root.rowCount()): masterItem = root.child(index, self.COL_NAME) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): self.addRow(master, is_local, root, index) doAddItem = False break if doAddItem: self.addRow(master, is_local, root, -1)
def updateTypeView(cls, service, item): ''' Updates the representation of the column contains the type of the service. :param service: the service data :type service: fkie_master_discovery.ServiceInfo<http://docs.ros.org/kinetic/api/fkie_master_discovery/html/modules.html#fkie_master_discovery.master_info.ServiceInfo> :param item: corresponding item in the model :type item: :class:`ServiceItem` ''' try: if service.isLocal and service.type: service_class = service.get_service_class( nm.is_local(get_hostname(service.uri))) item.setText(service_class._type) elif service.type: item.setText(service.type) else: item.setText('unknown type') # removed tooltip for clarity !!! # tooltip = '' # tooltip = ''.join([tooltip, '<h4>', service_class._type, '</h4>']) # tooltip = ''.join([tooltip, '<b><u>', 'Request', ':</u></b>']) # tooltip = ''.join([tooltip, '<dl><dt>', utf8(service_class._request_class.__slots__), '</dt></dl>']) # # tooltip = ''.join([tooltip, '<b><u>', 'Response', ':</u></b>']) # tooltip = ''.join([tooltip, '<dl><dt>', utf8(service_class._response_class.__slots__), '</dt></dl>']) # # item.setToolTip(''.join(['<div>', tooltip, '</div>'])) item.setToolTip('') except Exception: if not service.isLocal: tooltip = ''.join([ '<h4>', 'Service type is not available due to he running on another host.', '</h4>' ]) item.setToolTip(''.join(['<div>', tooltip, '</div>']))
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 on_save_profile(self, masteruri='', path=None): ''' Saves the current environment to a node manager profile. :param str masteruri: If not empty, save the profile only for given master :param str path: the path of file to save. If None :meth:`get_profile_file` is called to get a path. ''' try: if path is None: path = self.get_profile_file() if path is None: return rospy.loginfo("Save profile %s" % path) content = {} for muri, master in self._main_window.masters.items(): if not masteruri or masteruri == muri: running_nodes = master.get_nodes_runningIfLocal() configs = {} md_param = {} ms_param = {} zc_param = {} nmd_param = {} smuri = muri addr = nm.nameres().address(smuri) hostname = get_hostname(smuri) mastername = '' if nm.is_local(addr): smuri = smuri.replace(hostname, '$LOCAL$') addr = '$LOCAL$' else: mastername = nm.nameres().mastername( smuri, nm.nameres().address(smuri)) for node_name in running_nodes.keys(): node_items = master.getNode(node_name) for node in node_items: if node.is_running( ) and node.launched_cfg is not None: # node.has_launch_cfgs(node.cfgs): # it is a loaded launch file, get the filename cfg = to_pkg(node.launched_cfg) if cfg not in configs: configs[cfg] = {'nodes': []} configs[cfg]['nodes'].append(node_name) elif node_name.endswith('master_discovery'): md_param = get_rosparam( 'master_discovery', muri) elif node_name.endswith('master_sync'): ms_param = get_rosparam('master_sync', muri) elif node_name.endswith('zeroconf'): zc_param = get_rosparam('zeroconf', muri) elif node_name.endswith('node_manager_daemon'): nmd_param = get_rosparam( 'node_manager_daemon', muri) # store arguments for launchfiles for a, b in master.launchfiles.items(): resolved_a = to_pkg(a) if resolved_a not in configs: configs[resolved_a] = {} configs[resolved_a]['default'] = False configs[resolved_a]['args'] = b.args # fill the configuration content for yaml as dictionary content[smuri] = { 'mastername': mastername, 'address': addr, 'configs': configs } if md_param: content[smuri]['master_discovery'] = md_param if ms_param: content[smuri]['master_sync'] = ms_param if zc_param: content[smuri]['zeroconf'] = zc_param if nmd_param: content[smuri]['node_manager_daemon'] = nmd_param buf = ruamel.yaml.compat.StringIO() ruamel.yaml.dump(content, buf, Dumper=ruamel.yaml.RoundTripDumper) with open(path, 'w+') as f: f.write(buf.getvalue()) except Exception as e: import traceback print(utf8(traceback.format_exc(3))) MessageBox.warning(self, "Save profile Error", 'Error while save profile', utf8(e))