def summary(self, local=False): """ Get a human-readable string summary of the launch @param local bool: if True, only print local nodes @return: summary @rtype: str """ summary = '\nSUMMARY\n========' if self.clear_params: summary += '\n\nCLEAR PARAMETERS\n' + '\n'.join( [' * %s' % p for p in self.clear_params]) if self.params: summary += '\n\nPARAMETERS\n' + '\n'.join( [' * %s' % k for k in self.params]) if not local: summary += '\n\nMACHINES\n' + '\n'.join( [' * %s' % k for k in self.machines if k]) summary += '\n\nNODES\n' namespaces = {} if local: nodes = [n for n in self.nodes if is_machine_local(n.machine)] else: nodes = self.nodes for n in nodes: ns = n.namespace if ns not in namespaces: namespaces[ns] = [n] else: namespaces[ns].append(n) for k, v in namespaces.iteritems(): summary += ' %s\n' % k + '\n'.join( [' %s' % _summary_name(n) for n in v]) summary += '\n' return summary
def summary(self, local=False): """ Get a human-readable string summary of the launch @param local bool: if True, only print local nodes @return: summary @rtype: str """ summary = '\nSUMMARY\n========' if self.clear_params: summary += '\n\nCLEAR PARAMETERS\n' + '\n'.join([' * %s'%p for p in self.clear_params]) if self.params: summary += '\n\nPARAMETERS\n' + '\n'.join([' * %s'%k for k in self.params]) if not local: summary += '\n\nMACHINES\n' + '\n'.join([' * %s'%k for k in self.machines if k]) summary += '\n\nNODES\n' namespaces = {} if local: nodes = [n for n in self.nodes if is_machine_local(n.machine)] else: nodes = self.nodes for n in nodes: ns = n.namespace if ns not in namespaces: namespaces[ns] = [n] else: namespaces[ns].append(n) for k,v in namespaces.iteritems(): summary += ' %s\n'%k + '\n'.join([' %s'%_summary_name(n) for n in v]) summary += '\n' return summary
def start_children(self): """ Start the child roslaunch processes """ server_node_uri = self.server.uri if not server_node_uri: raise RLException("server URI is not initialized") # TODOXXX: break out table building code into a separate # routine so we can unit test it _start_child() should not be # determining the process name # Build table of unique machines that we are going to launch on machines = {} for n in self.rosconfig.nodes: if not is_machine_local(n.machine): machines[n.machine.config_key()] = n.machine # Launch child roslaunch processes on remote machines counter = 0 # - keep a list of procs so we can check for those that failed to launch procs = [] for m in machines: p = self._start_child(server_node_uri, machines[m], counter) procs.append(p) counter += 1 # Wait for all children to call register() callback. The machines can have # non-uniform registration timeouts. We consider the failure to occur once # one of the machines has failed to meet it's timeout. start_t = time.time() while True: pending = [] for p in procs: if not p.is_alive(): raise RLException("remote roslaunch failed to launch: %s"%p.machine.name) elif not p.uri: pending.append(p.machine) if not pending: break # timeout is the minimum of the remaining timeouts of the machines timeout_t = start_t + min([m.timeout for m in pending]) if time.time() > timeout_t: break time.sleep(0.1) if pending: raise RLException( """The following roslaunch remote processes failed to register: %s If this is a network latency issue, you may wish to consider setting <machine timeout="NUMBER OF SECONDS" ... /> in your launch"""%'\n'.join([" * %s (timeout %ss)"%(m.name, m.timeout) for m in pending])) # convert machine dictionary to a list self.machine_list = machines.values() # save a list of the remote processes self.remote_processes = procs
def launch_remote_nodes(self): """ Contact each child to launch remote nodes """ succeeded = [] failed = [] # initialize remote_nodes. we use the machine config key as # the key for the dictionary so that we can bin the nodes. self.remote_nodes = {} for m in self.machine_list: self.remote_nodes[m.config_key()] = [] # build list of nodes that will be launched by machine nodes = [ x for x in self.rosconfig.nodes if not is_machine_local(x.machine) ] for n in nodes: self.remote_nodes[n.machine.config_key()].append(n) for child in self.remote_processes: nodes = self.remote_nodes[child.machine.config_key()] body = '\n'.join([n.to_remote_xml() for n in nodes]) # force utf-8 encoding, #3799 xml = '<?xml version="1.0" encoding="utf-8"?>\n<launch>\n%s</launch>' % body if 0: print xml api = child.getapi() # TODO: timeouts try: self.logger.debug("sending [%s] XML [\n%s\n]" % (child.uri, xml)) code, msg, val = api.launch(xml) if code == 1: c_succ, c_fail = val succeeded.extend(c_succ) failed.extend(c_fail) else: printerrlog('error launching on [%s, uri %s]: %s' % (child.name, child.uri, msg)) self._assume_failed(nodes, failed) except socket.error, (errno, msg): printerrlog('error launching on [%s, uri %s]: %s' % (child.name, child.uri, str(msg))) self._assume_failed(nodes, failed) except socket.gaierror, (errno, msg): # usually errno == -2. See #815. child_host, _ = network.parse_http_host_and_port(child.uri) printerrlog( "Unable to contact remote roslaunch at [%s]. This is most likely due to a network misconfiguration with host lookups. Please make sure that you can contact '%s' from this machine" % (child.uri, child_host)) self._assume_failed(nodes, failed)
def launch_remote_nodes(self): """ Contact each child to launch remote nodes """ succeeded = [] failed = [] # initialize remote_nodes. we use the machine config key as # the key for the dictionary so that we can bin the nodes. self.remote_nodes = {} for m in self.machine_list: self.remote_nodes[m.config_key()] = [] # build list of nodes that will be launched by machine nodes = [x for x in self.rosconfig.nodes if not is_machine_local(x.machine)] for n in nodes: self.remote_nodes[n.machine.config_key()].append(n) for child in self.remote_processes: nodes = self.remote_nodes[child.machine.config_key()] body = '\n'.join([n.to_remote_xml() for n in nodes]) # #3799: force utf-8 encoding xml = '<?xml version="1.0" encoding="utf-8"?>\n<launch>\n%s</launch>'%body api = child.getapi() # TODO: timeouts try: self.logger.debug("sending [%s] XML [\n%s\n]"%(child.uri, xml)) code, msg, val = api.launch(xml) if code == 1: c_succ, c_fail = val succeeded.extend(c_succ) failed.extend(c_fail) else: printerrlog('error launching on [%s, uri %s]: %s'%(child.name, child.uri, msg)) self._assume_failed(nodes, failed) except socket.error as e: errno, msg = e printerrlog('error launching on [%s, uri %s]: %s'%(child.name, child.uri, str(msg))) self._assume_failed(nodes, failed) except socket.gaierror as e: errno, msg = e # usually errno == -2. See #815. child_host, _ = network.parse_http_host_and_port(child.uri) printerrlog("Unable to contact remote roslaunch at [%s]. This is most likely due to a network misconfiguration with host lookups. Please make sure that you can contact '%s' from this machine"%(child.uri, child_host)) self._assume_failed(nodes, failed) except Exception as e: printerrlog('error launching on [%s, uri %s]: %s'%(child.name, child.uri, str(e))) self._assume_failed(nodes, failed) return succeeded, failed
def assign_machines(self): """ Assign nodes to machines and determine whether or not there are any remote machines """ # don't repeat machine assignment if self._assign_machines_complete: return machine_unify_dict = {} self._assign_machines_complete = True # #653: current have to set all core nodes to local launch local_machine = self.machines[''] for n in self.nodes_core: n.machine = local_machine #for n in self.nodes_core + self.nodes + self.tests: for n in self.nodes + self.tests: m = self._select_machine(n) # if machines have the same config keys it means that they are identical except # for their name. we unify the machine assignments so that we don't use # extra resources. config_key = m.config_key() if config_key in machine_unify_dict: new_m = machine_unify_dict[config_key] if m != new_m: self.logger.info( "... changing machine assignment from [%s] to [%s] as they are equivalent", m.name, new_m.name) m = new_m else: machine_unify_dict[config_key] = m n.machine = m self.logger.info( "... selected machine [%s] for node of type [%s/%s]", m.name, n.package, n.type) # determine whether or not there are any machines we will need # to setup remote roslaunch clients for self._remote_nodes_present = False if [ m for m in machine_unify_dict.itervalues() if not is_machine_local(m) ]: self._remote_nodes_present = True
def assign_machines(self): """ Assign nodes to machines and determine whether or not there are any remote machines """ # don't repeat machine assignment if self._assign_machines_complete: return machine_unify_dict = {} self._assign_machines_complete = True # #653: current have to set all core nodes to local launch local_machine = self.machines[''] for n in self.nodes_core: n.machine = local_machine #for n in self.nodes_core + self.nodes + self.tests: for n in self.nodes + self.tests: m = self._select_machine(n) # if machines have the same config keys it means that they are identical except # for their name. we unify the machine assignments so that we don't use # extra resources. config_key = m.config_key() if config_key in machine_unify_dict: new_m = machine_unify_dict[config_key] if m != new_m: self.logger.info("... changing machine assignment from [%s] to [%s] as they are equivalent", m.name, new_m.name) m = new_m else: machine_unify_dict[config_key] = m n.machine = m self.logger.info("... selected machine [%s] for node of type [%s/%s]", m.name, n.package, n.type) # determine whether or not there are any machines we will need # to setup remote roslaunch clients for self._remote_nodes_present = False if [m for m in machine_unify_dict.itervalues() if not is_machine_local(m)]: self._remote_nodes_present = True