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 detect_version(package): ''' Try to detect the current version from git, installed VERSION/DATE files or package.xml ''' global VERSION global DATE if VERSION != 'unknown': return VERSION, DATE version = 'unknown' date = 'unknown' try: pkg_path = roslib.packages.get_pkg_dir(package) if pkg_path is not None and os.path.isfile("%s/VERSION" % pkg_path): try: with open("%s/VERSION" % pkg_path) as f: version = f.read() version = version.strip() with open("%s/DATE" % pkg_path) as f: datetag = f.read().split() if datetag: date = datetag[0] except Exception as err: print >> sys.stderr, "version detection error: %s" % err elif os.path.isdir("%s/../.git" % pkg_path): try: os.chdir(pkg_path) ps = SupervisedPopen([ 'git', 'describe', '--tags', '--dirty', '--always', '--abbrev=8' ], stdout=subprocess.PIPE, object_id='get git version') output = ps.stdout.read() version = output.strip() ps = SupervisedPopen(['git', 'show', '-s', '--format=%ci'], stdout=subprocess.PIPE, object_id='get git date') output = ps.stdout.read().split() if output: date = output[0] except Exception as err: print >> sys.stderr, "version detection error: %s" % err else: ppath = roslib.packages.find_resource(package, 'package.xml') if ppath: doc = dom.parse(ppath[0]) version_tags = doc.getElementsByTagName("version") if version_tags: version = version_tags[0].firstChild.data version = version else: print >> sys.stderr, "version detection: no version tag in package.xml found!" else: print >> sys.stderr, "version detection: package.xml not found!" except Exception as err: print >> sys.stderr, "version detection error: %s" % err VERSION = version DATE = date return version, date
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 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 _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 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 _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 ssh_x11_exec(self, host, cmd, title=None, user=None): ''' Executes a command on remote host using a terminal with X11 forwarding. @todo: establish connection using paramiko SSH library. @param host: the host @type host: C{str} @param cmd: the list with command and arguments @type cmd: C{[str,...]} @param title: the title of the new opened terminal, if it is None, no new terminal will be created @type title: C{str} or C{None} @param user: user name @return: the result of C{subprocess.Popen(command)} @see: U{http://docs.python.org/library/subprocess.html?highlight=subproces#subprocess} ''' with self.mutex: try: # workaround: use ssh in a terminal with X11 forward user = nm.settings().host_user(host) if user is None else user if host in self.SSH_AUTH: user = self.SSH_AUTH[host] # generate string for SSH command ssh_str = ' '.join([ '/usr/bin/ssh', '-aqtx', '-oClearAllForwardings=yes', '-oConnectTimeout=5', '-oStrictHostKeyChecking=no', '-oVerifyHostKeyDNS=no', '-oCheckHostIP=no', ''.join([user, '@', host]) ]) if title is not None: cmd_str = nm.settings().terminal_cmd( [ssh_str, ' '.join(cmd)], title) else: cmd_str = utf8(' '.join([ssh_str, ' '.join(cmd)])) rospy.loginfo("REMOTE x11 execute on %s: %s", host, cmd_str) return SupervisedPopen( shlex.split(cmd_str), object_id=utf8(title), description="REMOTE x11 execute on %s: %s" % (host, cmd_str)) except Exception: raise
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 })