def _check_platform_helper() -> Tuple[str, dict, dict]: """ Check ROS_DISTRO environment variables and distribution installed. :return: string of distro name, dict of distribution info, dict of release platforms info """ distro_name = os.environ.get('ROS_DISTRO') if not distro_name: doctor_error('ROS_DISTRO is not set.') return distro_name = distro_name.lower() u = rosdistro.get_index_url() if not u: doctor_error( 'Unable to access ROSDISTRO_INDEX_URL or DEFAULT_INDEX_URL. ' 'Check network setting to make sure machine is connected to internet.' ) return i = rosdistro.get_index(u) distro_info = i.distributions.get(distro_name) if not distro_info: doctor_warn(f'Distribution name {distro_name} is not found') return try: distro_data = rosdistro.get_distribution(i, distro_name).get_data() except AttributeError: distro_data = '' return distro_name, distro_info, distro_data
def check(self): """Check network configuration.""" result = Result() # check ifcfg import for windows and osx users try: ifcfg_ifaces = ifcfg.interfaces() except NameError: doctor_error('`ifcfg` module is not imported. ' 'Unable to run network check.') result.add_error() return result has_loopback, has_non_loopback, has_multicast = _check_network_config_helper( ifcfg_ifaces) if not _is_unix_like_platform(): if not has_loopback and not has_non_loopback: # no flags found, otherwise one of them should be True. doctor_error( 'No flags found. ' 'Run `ipconfig` on Windows or ' 'install `ifconfig` on Unix to check network interfaces.') result.add_error() return result if not has_loopback: doctor_error('No loopback IP address is found.') result.add_error() if not has_non_loopback: doctor_warn('Only loopback IP address is found.') result.add_warning() if not has_multicast: doctor_warn('No multicast IP address is found.') result.add_warning() return result
def report(self): """Print system and ROS network information.""" # check ifcfg import for windows and osx users try: ifcfg_ifaces = ifcfg.interfaces() except NameError: doctor_warn('ifcfg is not imported. Unable to generate network report.') return Report('') network_report = Report('NETWORK CONFIGURATION') for iface in ifcfg_ifaces.values(): for k, v in iface.items(): if v: network_report.add_to_report(k, v) return network_report
def check(self): """Check publisher and subscriber counts.""" result = Result() to_be_checked = _get_topic_names() with DirectNode(None) as node: for topic in to_be_checked: pub_count = node.count_publishers(topic) sub_count = node.count_subscribers(topic) if pub_count > sub_count: doctor_warn( f'Publisher without subscriber detected on {topic}.') result.add_warning() elif pub_count < sub_count: doctor_warn( f'Subscriber without publisher detected on {topic}.') result.add_warning() return result
def compare_versions(result: Result, local_packages: dict, distro_packages: dict): """ Return warning messages for PackageCheck, and info for PackageReport. :param: dictionary of local package name and version :param: dictionary of rosdistro package name and version :param: boolean value determines which output to populate, msgs or report :return: list of warning messages """ missing_req = '' missing_local = '' for name, local_ver_str in local_packages.items(): if not local_ver_str: missing_local += ' ' + name local_ver_str = '' required_ver_str = distro_packages.get(name, '') if not required_ver_str: missing_req += ' ' + name local_ver = version.parse(local_ver_str).base_version required_ver = version.parse(required_ver_str).base_version if local_ver < required_ver: doctor_warn(f'{name} has been updated to a new version.' f' local: {local_ver} <' f' required: {required_ver}') result.add_warning() if missing_req: if len(missing_req) > 100: doctor_warn('Cannot find required versions of packages: ' + textwrap.shorten(missing_req, width=100) + ' Use `ros2 doctor --report` to see full list.') else: doctor_warn('Cannot find required versions of packages: ' + missing_req) if missing_local: if len(missing_local) > 100: doctor_warn('Cannot find local versions of packages: ' + textwrap.shorten(missing_local, width=100) + ' Use `ros2 doctor --report` to see full list.') else: doctor_warn('Cannot find local versions of packages: ' + missing_local)
def get_distro_package_versions() -> dict: """ Return repos info using rosdistro API. :return: dictionary of rosdistro package name and version """ distro_name = os.environ.get('ROS_DISTRO') if not distro_name: doctor_error('ROS_DISTRO is not set.') return distro_name = distro_name.lower() url = rosdistro.get_index_url() if not url: doctor_error( 'Unable to access ROSDISTRO_INDEX_URL or DEFAULT_INDEX_URL. ' 'Check network setting to make sure machine is connected to internet.' ) return i = rosdistro.get_index(url) distro_info = rosdistro.get_distribution(i, distro_name) if not distro_info: doctor_warn(f'Distribution name {distro_name} is not found') return try: repos_info = distro_info.get_data().get('repositories') except AttributeError: doctor_warn('No repository information found.') return distro_package_vers = {} for package_name, info in repos_info.items(): try: release = info['release'] ver = release.get('version') if 'packages' in release: # Metapackage for package in release['packages']: distro_package_vers[package] = ver else: distro_package_vers[package_name] = ver except KeyError: pass return distro_package_vers
def check(self): """Check network configuration.""" result = Result() # check ifcfg import for windows and osx users ifcfg_ifaces = ifcfg.interfaces() has_loopback, has_non_loopback, has_multicast = _check_network_config_helper( ifcfg_ifaces) if not _is_unix_like_platform(): if not has_loopback and not has_non_loopback: # no flags found, otherwise one of them should be True. doctor_warn( 'Interface flags are not available on Windows. ' 'Run `ipconfig` to see what interfaces are available.') result.add_warning() return result if not has_loopback: doctor_error('No loopback IP address is found.') result.add_error() if not has_non_loopback: doctor_warn('Only loopback IP address is found.') result.add_warning() if not has_multicast: doctor_warn('No multicast IP address is found.') result.add_warning() return result
def check(self): """Check network configuration.""" result = Result() has_loopback = False has_non_loopback = False has_multicast = False for interface in psutil.net_if_addrs().keys(): flags = InterfaceFlags(interface) has_loopback |= flags.has_loopback has_non_loopback |= flags.has_non_loopback has_multicast |= flags.has_multicast if os.name != 'posix': if not has_loopback and not has_non_loopback: # no flags found, otherwise one of them should be True. doctor_warn( 'Interface flags are not available on Windows. ' 'Run `ipconfig` to see what interfaces are available.') result.add_warning() return result if not has_loopback: doctor_error('No loopback IP address is found.') result.add_error() if not has_non_loopback: doctor_warn('Only loopback IP address is found.') result.add_warning() if not has_multicast: doctor_warn('No multicast IP address is found.') result.add_warning() return result
def generate_reports(*, categories=None) -> List[Report]: """ Print all reports or reports of failed checks to terminal. :return: list of Report objects """ reports = [] for report_entry_pt in iter_entry_points('ros2doctor.report'): try: report_class = report_entry_pt.load() except (ImportError, UnknownExtra): doctor_warn('Report entry point %s fails to load.' % report_entry_pt.name) try: report_instance = report_class() except Exception: doctor_warn('Unable to instantiate report object from %s.' % report_entry_pt.name) try: report_category = report_instance.category() report = report_instance.report() if categories: if report_category in categories: reports.append(report) else: reports.append(report) except Exception: doctor_warn('Fail to call %s class functions.' % report_entry_pt.name) return reports
def generate_reports(*, categories=None) -> List[Report]: """ Print all reports or reports of failed checks to terminal. :return: list of Report objects """ reports = [] for report_entry_pt in importlib_metadata.entry_points().get( 'ros2doctor.report', []): try: report_class = report_entry_pt.load() except ImportError: doctor_warn( f'Report entry point {report_entry_pt.name} fails to load.') try: report_instance = report_class() except Exception: doctor_warn( f'Unable to instantiate report object from {report_entry_pt.name}.' ) try: report_category = report_instance.category() report = report_instance.report() if categories: if report_category in categories: reports.append(report) else: reports.append(report) except Exception: doctor_warn( f'Fail to call {report_entry_pt.name} class functions.') return reports
def run_checks(*, include_warnings=False) -> Tuple[Set[str], int, int]: """ Run all checks and return check results. :return: 3-tuple (categories of failed checks, number of failed checks, total number of checks) """ failed_cats = set() # remove repeating elements fail = 0 total = 0 for check_entry_pt in iter_entry_points('ros2doctor.checks'): try: check_class = check_entry_pt.load() except (ImportError, UnknownExtra): doctor_warn('Check entry point %s fails to load.' % check_entry_pt.name) try: check_instance = check_class() except Exception: doctor_warn('Unable to instantiate check object from %s.' % check_entry_pt.name) try: check_category = check_instance.category() result = check_instance.check() if result.error or (include_warnings and result.warning): fail += 1 failed_cats.add(check_category) total += 1 except Exception: doctor_warn('Fail to call %s class functions.' % check_entry_pt.name) return failed_cats, fail, total
def run_checks(*, include_warnings=False) -> Tuple[Set[str], int, int]: """ Run all checks and return check results. :return: 3-tuple (categories of failed checks, number of failed checks, total number of checks) """ fail_categories = set() # remove repeating elements fail = 0 total = 0 for check_entry_pt in importlib_metadata.entry_points().get( 'ros2doctor.checks', []): try: check_class = check_entry_pt.load() except ImportError: doctor_warn( f'Check entry point {check_entry_pt.name} fails to load.') try: check_instance = check_class() except Exception: doctor_warn( f'Unable to instantiate check object from {check_entry_pt.name}.' ) try: check_category = check_instance.category() result = check_instance.check() if result.error or (include_warnings and result.warning): fail += 1 fail_categories.add(check_category) total += 1 except Exception: doctor_warn(f'Fail to call {check_entry_pt.name} class functions.') return fail_categories, fail, total
def check(self): """Check publisher and subscriber counts.""" result = Result() to_be_checked = get_topic_names() with NodeStrategy(None) as node: for topic in to_be_checked: for pub in node.get_publishers_info_by_topic(topic): for sub in node.get_subscriptions_info_by_topic(topic): compatibility, reason = qos_check_compatible( pub.qos_profile, sub.qos_profile) reason_message = self._strip_leading_warning_or_error_from_string( reason) if compatibility == QoSCompatibility.WARNING: doctor_warn( f"QoS compatibility warning found on topic '{topic}': " f'{reason_message}') result.add_warning() elif compatibility == QoSCompatibility.ERROR: doctor_error( f"QoS compatibility error found on topic '{topic}': " f'{reason_message}') result.add_error() return result
def check(self): """Check system platform against ROS 2 Distro.""" result = Result() distros = _check_platform_helper() if not distros: doctor_error('Missing rosdistro info. Unable to check platform.') result.add_error() return result distro_name, distro_info, _ = distros # check distro status if distro_info.get('distribution_status') == 'prerelease': doctor_warn( f'Distribution {distro_name} is not fully supported or tested. ' 'To get more consistent features, download a stable version at ' 'https://index.ros.org/doc/ros2/Installation/') result.add_warning() elif distro_info.get('distribution_status') == 'end-of-life': doctor_warn( f'Distribution {distro_name} is no longer supported or deprecated. ' 'To get the latest features, download the new versions at ' 'https://index.ros.org/doc/ros2/Installation/') result.add_warning() return result
def _check_platform_helper() -> Tuple[str, dict, dict]: """ Check ROS_DISTRO environment variables and distribution installed. :return: string of distro name, dict of distribution info, dict of release platforms info """ distro_name = os.environ.get('ROS_DISTRO') if not distro_name: doctor_warn('ROS_DISTRO is not set.') return else: distro_name = distro_name.lower() u = rosdistro.get_index_url() if not u: doctor_warn( 'Unable to access ROSDISTRO_INDEX_URL or DEFAULT_INDEX_URL.') return i = rosdistro.get_index(u) distro_info = i.distributions.get(distro_name) if not distro_info: doctor_warn("Distribution name '%s' is not found" % distro_name) return distro_data = rosdistro.get_distribution(i, distro_name).get_data() return distro_name, distro_info, distro_data
import os from typing import Tuple from ros2doctor.api import DoctorCheck from ros2doctor.api import DoctorReport from ros2doctor.api import Report from ros2doctor.api import Result from ros2doctor.api.format import doctor_error from ros2doctor.api.format import doctor_warn try: import ifcfg except ImportError: # check import error for windows and osx doctor_warn( 'Unable to import ifcfg. ' 'Use `python3 -m pip install ifcfg` to install needed package.') def _is_unix_like_platform() -> bool: """Return True if conforms to UNIX/POSIX-style APIs.""" return os.name == 'posix' def _check_network_config_helper( ifcfg_ifaces: dict) -> Tuple[bool, bool, bool]: """Check if loopback and multicast IP addresses are found.""" has_loopback, has_non_loopback, has_multicast = False, False, False for iface in ifcfg_ifaces.values(): flags = iface.get('flags') if flags:
def add_error(self, msg) -> None: doctor_warn(msg) self.error += 1
# See the License for the specific language governing permissions and # limitations under the License. import os from typing import Tuple from ros2doctor.api import DoctorCheck from ros2doctor.api import DoctorReport from ros2doctor.api import Report from ros2doctor.api import Result from ros2doctor.api.format import doctor_warn try: import ifcfg except ImportError: # check import error for windows and osx doctor_warn('Failed to import ifcfg. ' 'Use `python -m pip install ifcfg` to install needed package.') def _is_unix_like_platform() -> bool: """Return True if conforms to UNIX/POSIX-style APIs.""" return os.name == 'posix' def _check_network_config_helper(ifcfg_ifaces: dict) -> Tuple[bool, bool, bool]: """Check if loopback and multicast IP addresses are found.""" has_loopback, has_non_loopback, has_multicast = False, False, False for iface in ifcfg_ifaces.values(): flags = iface.get('flags') if flags: flags = flags.lower() if 'loopback' in flags:
def add_warning(self, msg) -> None: doctor_warn(msg) self.warning += 1