diff --git a/ros2doctor/package.xml b/ros2doctor/package.xml index 90f3b5810..47101106f 100644 --- a/ros2doctor/package.xml +++ b/ros2doctor/package.xml @@ -9,7 +9,7 @@ ros2cli - python3-numpy + ifcfg_vendor python3-rosdistro-modules ament_copyright diff --git a/ros2doctor/ros2doctor/api/format.py b/ros2doctor/ros2doctor/api/format.py new file mode 100644 index 000000000..7241fca7b --- /dev/null +++ b/ros2doctor/ros2doctor/api/format.py @@ -0,0 +1,20 @@ +# Copyright 2019 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def print_term(k, v): + """Print term only if it exists.""" + if v: + # TODO(clairewang): 20 padding needs to be dynamically set + print('{:20}: {}'.format(k, v)) diff --git a/ros2doctor/ros2doctor/api/network.py b/ros2doctor/ros2doctor/api/network.py new file mode 100644 index 000000000..682671fc6 --- /dev/null +++ b/ros2doctor/ros2doctor/api/network.py @@ -0,0 +1,60 @@ +# Copyright 2019 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys + +import ifcfg + +from ros2doctor.api.format import print_term + + +def _is_unix_like_platform(): + """Return True if conforms to UNIX/POSIX-style APIs.""" + return os.name == 'posix' + + +def check_network_config_helper(): + """Check if loopback and multicast IP addresses are found.""" + has_loopback, has_non_loopback, has_multicast = False, False, False + for name, iface in ifcfg.interfaces().items(): + flags = iface.get('flags') + if 'LOOPBACK' in flags: + has_loopback = True + else: + has_non_loopback = True + if 'MULTICAST' in flags: + has_multicast = True + return has_loopback, has_non_loopback, has_multicast + + +def check_network_config(): + """Conduct network checks and output error/warning messages.""" + has_loopback, has_non_loopback, has_multicast = check_network_config_helper() + if not has_loopback: + sys.stderr.write('ERROR: No loopback IP address is found.\n') + if not has_non_loopback: + sys.stderr.write('WARNING: Only loopback IP address is found.\n') + if not has_multicast: + sys.stderr.write('WARNING: No multicast IP address is found.\n') + return has_loopback and has_non_loopback and has_multicast + + +def print_network(): + """Print all system and ROS network information.""" + print('NETWORK CONFIGURATION') + for name, iface in ifcfg.interfaces().items(): + for k, v in iface.items(): + print_term(k, v) + print('\n') diff --git a/ros2doctor/ros2doctor/api/platform.py b/ros2doctor/ros2doctor/api/platform.py index 02d879fb7..cd31b5a53 100644 --- a/ros2doctor/ros2doctor/api/platform.py +++ b/ros2doctor/ros2doctor/api/platform.py @@ -16,6 +16,8 @@ import platform import sys +from ros2doctor.api.format import print_term + import rosdistro @@ -24,37 +26,38 @@ def print_platform_info(): platform_name = platform.system() # platform info print('PLATFORM INFORMATION') - print('system : ', platform_name) - print('Platform Info : ', platform.platform()) + print_term('system', platform_name) + print_term('platform info', platform.platform()) if platform_name == 'Darwin': - print('Mac OS version : ', platform.mac_ver()) - print('release : ', platform.release()) - print('processor : ', platform.processor()) + print_term('mac OS version', platform.mac_ver()) + print_term('release', platform.release()) + print_term('processor', platform.processor()) # python info print('PYTHON INFORMATION') - print('version : ', platform.python_version()) - print('compiler : ', platform.python_compiler()) - print('build : ', platform.python_build()) + print_term('version', platform.python_version()) + print_term('compiler', platform.python_compiler()) + print_term('build', platform.python_build()) + print('\n') def check_platform_helper(): """Check ROS_DISTRO related environment variables and distribution name.""" distro_name = os.environ.get('ROS_DISTRO') if not distro_name: - sys.stderr.write('WARNING: ROS_DISTRO is not set.') + sys.stderr.write('WARNING: ROS_DISTRO is not set.\n') return else: distro_name = distro_name.lower() u = rosdistro.get_index_url() if not u: - sys.stderr.write('WARNING: Unable to access ROSDISTRO_INDEX_URL\ - or DEFAULT_INDEX_URL.') + sys.stderr.write('WARNING: Unable to access ROSDISTRO_INDEX_URL ' + 'or DEFAULT_INDEX_URL.\n') return i = rosdistro.get_index(u) distro_info = i.distributions.get(distro_name) if not distro_info: - sys.stderr.write("WARNING: Distribution name '%s' is not found" % distro_name) + sys.stderr.write("WARNING: Distribution name '%s' is not found\n" % distro_name) return distro_data = rosdistro.get_distribution(i, distro_name).get_data() return distro_name, distro_info, distro_data @@ -68,10 +71,11 @@ def print_ros2_info(): distro_name, distro_info, distro_data = distros print('ROS INFORMATION') - print('distribution name : ', distro_name) - print('distribution type : ', distro_info.get('distribution_type')) - print('distribution status : ', distro_info.get('distribution_status')) - print('release platforms : ', distro_data.get('release_platforms')) + print_term('distribution name', distro_name) + print_term('distribution type', distro_info.get('distribution_type')) + print_term('distribution status', distro_info.get('distribution_status')) + print_term('release platforms', distro_data.get('release_platforms')) + print('\n') def check_platform(): @@ -84,15 +88,13 @@ def check_platform(): # check distro status if distro_info.get('distribution_status') == 'prerelease': - sys.stderr.write('WARNING: Distribution is not fully supported or tested.\ - To get more stable features,\ - Download a stable version at\ - https://index.ros.org/doc/ros2/Installation/') + sys.stderr.write('WARNING: Distribution is not fully supported or tested. ' + 'To get more stable features, download a stable version at ' + 'https://index.ros.org/doc/ros2/Installation/\n') elif distro_info.get('distribution_status') == 'end-of-life': - sys.stderr.write('WARNING: Distribution is no longer supported or deprecated.\ - To get the latest features,\ - Download the latest version at\ - https://index.ros.org/doc/ros2/Installation/') + sys.stderr.write('WARNING: Distribution is no longer supported or deprecated. ' + 'To get the latest features, download the latest version at ' + 'https://index.ros.org/doc/ros2/Installation/') else: passed = True return passed diff --git a/ros2doctor/ros2doctor/command/doctor.py b/ros2doctor/ros2doctor/command/doctor.py index 43f01b3e8..3cbf00551 100644 --- a/ros2doctor/ros2doctor/command/doctor.py +++ b/ros2doctor/ros2doctor/command/doctor.py @@ -41,6 +41,6 @@ def main(self, *, parser, args): class WtfCommand(DoctorCommand): - """Add `wtf` as alias to `doctor`.""" + """Use `wtf` as alias to `doctor`.""" pass diff --git a/ros2doctor/setup.py b/ros2doctor/setup.py index 41efa6b03..200842c48 100644 --- a/ros2doctor/setup.py +++ b/ros2doctor/setup.py @@ -32,10 +32,12 @@ ], 'ros2doctor.checks': [ 'check_platform = ros2doctor.api.platform:check_platform', + 'check_network_config = ros2doctor.api.network:check_network_config', ], 'ros2doctor.report': [ 'report_platform = ros2doctor.api.platform:print_platform_info', 'report_ros_distro = ros2doctor.api.platform:print_ros2_info', + 'report_network_config = ros2doctor.api.network:print_network', ], } )