Package roswtf :: Module roslaunchwtf
[frames] | no frames]

Source Code for Module roswtf.roslaunchwtf

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2009, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  # 
 33  # Revision $Id$ 
 34   
 35  import os 
 36  import itertools 
 37  import socket 
 38  import stat 
 39  import sys 
 40  try: 
 41      from xmlrpc.client import ServerProxy 
 42  except ImportError: 
 43      from xmlrpclib import ServerProxy 
 44   
 45  from os.path import isfile, isdir 
 46   
 47  import roslib.packages 
 48  import roslaunch 
 49  import roslaunch.netapi 
 50   
 51  from roswtf.environment import paths, is_executable 
 52  from roswtf.rules import warning_rule, error_rule 
 53   
 54  ## check if node is cannot be located in package 
55 -def roslaunch_missing_node_check(ctx):
56 nodes = [] 57 for filename, rldeps in ctx.launch_file_deps.items(): 58 nodes.extend(rldeps.nodes) 59 errors = [] 60 for pkg, node_type in nodes: 61 paths = roslib.packages.find_node(pkg, node_type) 62 if not paths: 63 errors.append("node [%s] in package [%s]"%(node_type, pkg)) 64 return errors
65 66 ## check if two nodes with same name in package
67 -def roslaunch_duplicate_node_check(ctx):
68 nodes = [] 69 for filename, rldeps in ctx.launch_file_deps.items(): 70 nodes.extend(rldeps.nodes) 71 warnings = [] 72 for pkg, node_type in nodes: 73 paths = roslib.packages.find_node(pkg, node_type) 74 if len(paths) > 1: 75 warnings.append("node [%s] in package [%s]\n"%(node_type, pkg)) 76 return warnings
77
78 -def pycrypto_check(ctx):
79 try: 80 import Crypto 81 except ImportError as e: 82 return True
83
84 -def paramiko_check(ctx):
85 try: 86 import paramiko 87 except ImportError as e: 88 return True
89 -def paramiko_system_keys(ctx):
90 try: 91 import paramiko 92 ssh = paramiko.SSHClient() 93 try: 94 ssh.load_system_host_keys() #default location 95 except: 96 return True 97 except: pass
98
99 -def paramiko_ssh(ctx, address, port, username, password):
100 try: 101 import paramiko 102 ssh = paramiko.SSHClient() 103 104 import roslaunch.remoteprocess 105 err_msg = roslaunch.remoteprocess.ssh_check_known_hosts(ssh, address, port, username=username) 106 if err_msg: 107 return err_msg 108 109 if not password: #use SSH agent 110 ssh.connect(address, port, username) 111 else: #use SSH with login/pass 112 ssh.connect(address, port, username, password) 113 114 except paramiko.BadHostKeyException: 115 return "Unable to verify host key for [%s:%s]"%(address, port) 116 except paramiko.AuthenticationException: 117 return "Authentication to [%s:%s] failed"%(address, port) 118 except paramiko.SSHException as e: 119 return "[%s:%s]: %s"%(address, port, e) 120 except ImportError: 121 pass
122
123 -def _load_roslaunch_config(ctx):
124 config = roslaunch.ROSLaunchConfig() 125 loader = roslaunch.XmlLoader() 126 # TODO load roscore 127 for launch_file in ctx.launch_files: 128 loader.load(launch_file, config, verbose=False) 129 try: 130 config.assign_machines() 131 except roslaunch.RLException as e: 132 return config, [] 133 machines = [] 134 for n in itertools.chain(config.nodes, config.tests): 135 if n.machine not in machines: 136 machines.append(n.machine) 137 return config, machines
138
139 -def roslaunch_load_check(ctx):
140 config = roslaunch.ROSLaunchConfig() 141 loader = roslaunch.XmlLoader() 142 # TODO load roscore 143 for launch_file in ctx.launch_files: 144 loader.load(launch_file, config, verbose=False) 145 try: 146 config.assign_machines() 147 except roslaunch.RLException as e: 148 return str(e)
149
150 -def roslaunch_machine_name_check(ctx):
151 config, machines = _load_roslaunch_config(ctx) 152 bad = [] 153 for m in machines: 154 try: 155 #TODO IPV6: only check for IPv6 when IPv6 is enabled 156 socket.getaddrinfo(m.address, 0, 0, 0, socket.SOL_TCP) 157 except socket.gaierror: 158 bad.append(m.address) 159 return ''.join([' * %s\n'%b for b in bad])
160
161 -def roslaunch_ssh_check(ctx):
162 import roslaunch.core 163 if not ctx.launch_files: 164 return # not relevant 165 config, machines = _load_roslaunch_config(ctx) 166 err_msgs = [] 167 for m in machines: 168 socket.setdefaulttimeout(3.) 169 # only check if the machine requires ssh to connect 170 if not roslaunch.core.is_machine_local(m): 171 err_msg = paramiko_ssh(ctx, m.address, m.ssh_port, m.user, m.password) 172 if err_msg: 173 err_msgs.append(err_msg) 174 return err_msgs
175
176 -def roslaunch_missing_pkgs_check(ctx):
177 # rospack depends does not return depends that it cannot find, so 178 # we have to manually determine this 179 config, machines = _load_roslaunch_config(ctx) 180 missing = [] 181 for n in config.nodes: 182 pkg = n.package 183 try: 184 roslib.packages.get_pkg_dir(pkg, required=True) 185 except: 186 missing.append(pkg) 187 return missing
188
189 -def roslaunch_config_errors(ctx):
190 config, machines = _load_roslaunch_config(ctx) 191 return config.config_errors
192
193 -def roslaunch_missing_deps_check(ctx):
194 missing = [] 195 for pkg, miss in ctx.launch_file_missing_deps.items(): 196 if miss: 197 missing.append("%s/manifest.xml: %s"%(pkg, ', '.join(miss))) 198 return missing
199
200 -def roslaunch_respawn_check(ctx):
201 respawn = [] 202 for uri in ctx.roslaunch_uris: 203 try: 204 r = ServerProxy(uri) 205 code, msg, val = r.list_processes() 206 active, _ = val 207 respawn.extend([a for a in active if a[1] > 1]) 208 #TODO: children processes 209 #code, msg, val = r.list_children() 210 except: 211 pass # error for another rule 212 return ["%s (%s)"%(a[0], a[1]) for a in respawn]
213
214 -def roslaunch_uris_check(ctx):
215 # check for any roslaunch processes that cannot be contacted 216 bad = [] 217 # uris only contains the parent launches 218 for uri in ctx.roslaunch_uris: 219 try: 220 r = ServerProxy(uri) 221 code, msg, val = r.list_children() 222 # check the children launches 223 if code == 1: 224 for child_uri in val: 225 try: 226 r = ServerProxy(uri) 227 code, msg, val = r.get_pid() 228 except: 229 bad.append(child_uri) 230 except: 231 bad.append(uri) 232 return bad
233
234 -def roslaunch_dead_check(ctx):
235 dead = [] 236 for uri in ctx.roslaunch_uris: 237 try: 238 r = ServerProxy(uri) 239 code, msg, val = r.list_processes() 240 _, dead_list = val 241 dead.extend([d[0] for d in dead_list]) 242 #TODO: children processes 243 #code, msg, val = r.list_children() 244 except: 245 pass # error for another rule 246 return dead
247 248 online_roslaunch_warnings = [ 249 (roslaunch_respawn_check,"These nodes have respawned at least once:"), 250 (roslaunch_dead_check,"These nodes have died:"), 251 # disabling for now as roslaunches don't do cleanup 252 #(roslaunch_uris_check,"These roslaunch processes can no longer be contacted and may have exited:"), 253 ] 254 255 online_roslaunch_errors = [ 256 (roslaunch_ssh_check,"SSH failures:"), 257 ] 258 259 static_roslaunch_warnings = [ 260 (roslaunch_duplicate_node_check, "Multiple nodes of same name in packages:"), 261 (pycrypto_check, "pycrypto is not installed"), 262 (paramiko_check, "paramiko is not installed"), 263 (paramiko_system_keys, "cannot load SSH host keys -- your known_hosts file may be corrupt") , 264 (roslaunch_config_errors, "Loading your launch files reported the following configuration errors:"), 265 ] 266 static_roslaunch_errors = [ 267 # Disabling, because we've removed package dependencies from manifests. 268 #(roslaunch_missing_deps_check, 269 # "Package %(pkg)s is missing roslaunch dependencies.\nPlease add the following tags to %(pkg)s/manifest.xml:"), 270 (roslaunch_missing_pkgs_check, 271 "Cannot find the following required packages:"), 272 (roslaunch_missing_node_check, "Several nodes in your launch file could not be located. These are either typed incorrectly or need to be built:"), 273 (roslaunch_machine_name_check,"Cannot resolve the following hostnames:"), 274 (roslaunch_load_check, "roslaunch load failed"), 275 ] 276
277 -def wtf_check_static(ctx):
278 if not ctx.launch_files: 279 return 280 281 #NOTE: roslaunch files are already loaded separately into context 282 283 #TODO: check each machine name 284 #TODO: bidirectional ping for each machine 285 286 for r in static_roslaunch_warnings: 287 warning_rule(r, r[0](ctx), ctx) 288 for r in static_roslaunch_errors: 289 error_rule(r, r[0](ctx), ctx)
290
291 -def _load_online_ctx(ctx):
292 ctx.roslaunch_uris = roslaunch.netapi.get_roslaunch_uris()
293
294 -def wtf_check_online(ctx):
295 _load_online_ctx(ctx) 296 if not ctx.roslaunch_uris: 297 return 298 for r in online_roslaunch_warnings: 299 warning_rule(r, r[0](ctx), ctx) 300 for r in online_roslaunch_errors: 301 error_rule(r, r[0](ctx), ctx)
302