Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
 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
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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:
Ejemplo n.º 17
0
 def add_error(self, msg) -> None:
     doctor_warn(msg)
     self.error += 1
Ejemplo n.º 18
0
# 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:
Ejemplo n.º 19
0
 def add_warning(self, msg) -> None:
     doctor_warn(msg)
     self.warning += 1