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  import xmlrpclib 
 41   
 42  from os.path import isfile, isdir 
 43   
 44  import roslib.packages 
 45  import roslaunch 
 46  import roslaunch.netapi 
 47   
 48  from roswtf.environment import paths, is_executable 
 49  from roswtf.rules import warning_rule, error_rule 
 50   
 51  ## check if node is cannot be located in package 
52 -def roslaunch_missing_node_check(ctx):
53 nodes = [] 54 for filename, rldeps in ctx.launch_file_deps.iteritems(): 55 nodes.extend(rldeps.nodes) 56 errors = [] 57 for pkg, node_type in nodes: 58 paths = roslib.packages.find_node(pkg, node_type) 59 if not paths: 60 errors.append("node [%s] in package [%s]"%(node_type, pkg)) 61 return errors
62 63 ## check if two nodes with same name in package
64 -def roslaunch_duplicate_node_check(ctx):
65 nodes = [] 66 for filename, rldeps in ctx.launch_file_deps.iteritems(): 67 nodes.extend(rldeps.nodes) 68 warnings = [] 69 for pkg, node_type in nodes: 70 paths = roslib.packages.find_node(pkg, node_type) 71 if len(paths) > 1: 72 warnings.append("node [%s] in package [%s]\n"%(node_type, pkg)) 73 return warnings
74
75 -def pycrypto_check(ctx):
76 try: 77 import Crypto 78 except ImportError as e: 79 return True
80
81 -def paramiko_check(ctx):
82 try: 83 import paramiko 84 except ImportError as e: 85 return True
86 -def paramiko_system_keys(ctx):
87 try: 88 import paramiko 89 ssh = paramiko.SSHClient() 90 try: 91 ssh.load_system_host_keys() #default location 92 except: 93 return True 94 except: pass
95
96 -def paramiko_ssh(ctx, address, port, username, password):
97 try: 98 import paramiko 99 ssh = paramiko.SSHClient() 100 101 import roslaunch.remoteprocess 102 err_msg = roslaunch.remoteprocess.ssh_check_known_hosts(ssh, address, port, username=username) 103 if err_msg: 104 return err_msg 105 106 if not password: #use SSH agent 107 ssh.connect(address, port, username) 108 else: #use SSH with login/pass 109 ssh.connect(address, port, username, password) 110 111 except paramiko.BadHostKeyException: 112 return "Unable to verify host key for [%s:%s]"%(address, port) 113 except paramiko.AuthenticationException: 114 return "Authentication to [%s:%s] failed"%(address, port) 115 except paramiko.SSHException as e: 116 return "[%s:%s]: %s"%(address, port, e) 117 except ImportError: 118 pass
119
120 -def _load_roslaunch_config(ctx):
121 config = roslaunch.ROSLaunchConfig() 122 loader = roslaunch.XmlLoader() 123 # TODO load roscore 124 for launch_file in ctx.launch_files: 125 loader.load(launch_file, config, verbose=False) 126 try: 127 config.assign_machines() 128 except roslaunch.RLException as e: 129 return config, [] 130 machines = [] 131 for n in itertools.chain(config.nodes, config.tests): 132 if n.machine not in machines: 133 machines.append(n.machine) 134 return config, machines
135
136 -def roslaunch_load_check(ctx):
137 config = roslaunch.ROSLaunchConfig() 138 loader = roslaunch.XmlLoader() 139 # TODO load roscore 140 for launch_file in ctx.launch_files: 141 loader.load(launch_file, config, verbose=False) 142 try: 143 config.assign_machines() 144 except roslaunch.RLException as e: 145 return str(e)
146
147 -def roslaunch_machine_name_check(ctx):
148 config, machines = _load_roslaunch_config(ctx) 149 bad = [] 150 for m in machines: 151 try: 152 #TODO IPV6: only check for IPv6 when IPv6 is enabled 153 socket.getaddrinfo(m.address, 0, 0, 0, socket.SOL_TCP) 154 except socket.gaierror: 155 bad.append(m.address) 156 return ''.join([' * %s\n'%b for b in bad])
157
158 -def roslaunch_ssh_check(ctx):
159 import roslaunch.core 160 if not ctx.launch_files: 161 return # not relevant 162 config, machines = _load_roslaunch_config(ctx) 163 err_msgs = [] 164 for m in machines: 165 socket.setdefaulttimeout(3.) 166 # only check if the machine requires ssh to connect 167 if not roslaunch.core.is_machine_local(m): 168 err_msg = paramiko_ssh(ctx, m.address, m.ssh_port, m.user, m.password) 169 if err_msg: 170 err_msgs.append(err_msg) 171 return err_msgs
172
173 -def roslaunch_missing_pkgs_check(ctx):
174 # rospack depends does not return depends that it cannot find, so 175 # we have to manually determine this 176 config, machines = _load_roslaunch_config(ctx) 177 missing = [] 178 for n in config.nodes: 179 pkg = n.package 180 try: 181 roslib.packages.get_pkg_dir(pkg, required=True) 182 except: 183 missing.append(pkg) 184 return missing
185
186 -def roslaunch_config_errors(ctx):
187 config, machines = _load_roslaunch_config(ctx) 188 return config.config_errors
189
190 -def roslaunch_missing_deps_check(ctx):
191 missing = [] 192 for pkg, miss in ctx.launch_file_missing_deps.iteritems(): 193 if miss: 194 missing.append("%s/manifest.xml: %s"%(pkg, ', '.join(miss))) 195 return missing
196
197 -def roslaunch_respawn_check(ctx):
198 respawn = [] 199 for uri in ctx.roslaunch_uris: 200 try: 201 r = xmlrpclib.ServerProxy(uri) 202 code, msg, val = r.list_processes() 203 active, _ = val 204 respawn.extend([a for a in active if a[1] > 1]) 205 #TODO: children processes 206 #code, msg, val = r.list_children() 207 except: 208 pass # error for another rule 209 return ["%s (%s)"%(a[0], a[1]) for a in respawn]
210
211 -def roslaunch_uris_check(ctx):
212 # check for any roslaunch processes that cannot be contacted 213 bad = [] 214 # uris only contains the parent launches 215 for uri in ctx.roslaunch_uris: 216 try: 217 r = xmlrpclib.ServerProxy(uri) 218 code, msg, val = r.list_children() 219 # check the children launches 220 if code == 1: 221 for child_uri in val: 222 try: 223 r = xmlrpclib.ServerProxy(uri) 224 code, msg, val = r.get_pid() 225 except: 226 bad.append(child_uri) 227 except: 228 bad.append(uri) 229 return bad
230
231 -def roslaunch_dead_check(ctx):
232 dead = [] 233 for uri in ctx.roslaunch_uris: 234 try: 235 r = xmlrpclib.ServerProxy(uri) 236 code, msg, val = r.list_processes() 237 _, dead_list = val 238 dead.extend([d[0] for d in dead_list]) 239 #TODO: children processes 240 #code, msg, val = r.list_children() 241 except: 242 pass # error for another rule 243 return dead
244 245 online_roslaunch_warnings = [ 246 (roslaunch_respawn_check,"These nodes have respawned at least once:"), 247 (roslaunch_dead_check,"These nodes have died:"), 248 # disabling for now as roslaunches don't do cleanup 249 #(roslaunch_uris_check,"These roslaunch processes can no longer be contacted and may have exited:"), 250 ] 251 252 online_roslaunch_errors = [ 253 (roslaunch_ssh_check,"SSH failures:"), 254 ] 255 256 static_roslaunch_warnings = [ 257 (roslaunch_duplicate_node_check, "Multiple nodes of same name in packages:"), 258 (pycrypto_check, "pycrypto is not installed"), 259 (paramiko_check, "paramiko is not installed"), 260 (paramiko_system_keys, "cannot load SSH host keys -- your known_hosts file may be corrupt") , 261 (roslaunch_config_errors, "Loading your launch files reported the following configuration errors:"), 262 ] 263 static_roslaunch_errors = [ 264 # Disabling, because we've removed package dependencies from manifests. 265 #(roslaunch_missing_deps_check, 266 # "Package %(pkg)s is missing roslaunch dependencies.\nPlease add the following tags to %(pkg)s/manifest.xml:"), 267 (roslaunch_missing_pkgs_check, 268 "Cannot find the following required packages:"), 269 (roslaunch_missing_node_check, "Several nodes in your launch file could not be located. These are either typed incorrectly or need to be built:"), 270 (roslaunch_machine_name_check,"Cannot resolve the following hostnames:"), 271 (roslaunch_load_check, "roslaunch load failed"), 272 ] 273
274 -def wtf_check_static(ctx):
275 if not ctx.launch_files: 276 return 277 278 #NOTE: roslaunch files are already loaded separately into context 279 280 #TODO: check each machine name 281 #TODO: bidirectional ping for each machine 282 283 for r in static_roslaunch_warnings: 284 warning_rule(r, r[0](ctx), ctx) 285 for r in static_roslaunch_errors: 286 error_rule(r, r[0](ctx), ctx)
287
288 -def _load_online_ctx(ctx):
289 ctx.roslaunch_uris = roslaunch.netapi.get_roslaunch_uris()
290
291 -def wtf_check_online(ctx):
292 _load_online_ctx(ctx) 293 for r in online_roslaunch_warnings: 294 warning_rule(r, r[0](ctx), ctx) 295 for r in online_roslaunch_errors: 296 error_rule(r, r[0](ctx), ctx)
297