Ejemplo n.º 1
0
def process():
    conflicts = _detect_dracut_modules_conflicts(UpgradeInitramfsTasks)
    if conflicts:
        report = [
            reporting.Title(
                'Conflicting requirements of dracut modules for the upgrade initramfs'
            ),
            reporting.Summary(
                SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
        ]
        reporting.create_report(report)

    conflicts = _detect_dracut_modules_conflicts(TargetInitramfsTasks)
    if conflicts:
        report = [
            reporting.Title(
                'Conflicting requirements of dracut modules for the target initramfs'
            ),
            reporting.Summary(
                SUMMARY_DRACUT_FMT.format(_printable_modules(conflicts))),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
        ]
        reporting.create_report(report)
def process():
    kernel_name = 'kernel'
    if version.is_rhel_realtime():
        api.current_logger().info('The Real Time kernel boot detected.')
        kernel_name = 'kernel-rt'

    pkgs = get_pkgs(kernel_name)
    if not pkgs:
        # Hypothatical, user is not allowed to install any kernel that is not signed by RH
        # In case we would like to be cautious, we could check whether there are no other
        # kernels installed as well.
        api.current_logger().error(
            'Cannot find any installed kernel signed by Red Hat.')
        raise StopActorExecutionError(
            'Cannot find any installed kernel signed by Red Hat.')

    if len(pkgs) > 1 and architecture.matches_architecture(
            architecture.ARCH_S390X):
        # It's temporary solution, so no need to try automatize everything.
        title = 'Multiple kernels installed'
        summary = (
            'The upgrade process does not handle well the case when multiple kernels'
            ' are installed on s390x. There is a severe risk of the bootloader configuration'
            ' getting corrupted during the upgrade.')
        remediation = (
            'Boot into the most up-to-date kernel and remove all older'
            ' kernels installed on the machine before running Leapp again.')
        reporting.create_report([
            reporting.Title(title),
            reporting.Summary(summary),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.KERNEL, reporting.Tags.BOOT]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Remediation(hint=remediation),
            reporting.RelatedResource('package', 'kernel')
        ])

    current_evr = get_current_kernel_evr()
    newest_evr = get_newest_evr(pkgs)

    api.current_logger().debug('Current kernel EVR: {}'.format(current_evr))
    api.current_logger().debug('Newest kernel EVR: {}'.format(newest_evr))

    if current_evr != newest_evr:
        title = 'Newest installed kernel not in use'
        summary = ('To ensure a stable upgrade, the machine needs to be'
                   ' booted into the latest installed kernel.')
        remediation = ('Boot into the most up-to-date kernel installed'
                       ' on the machine before running Leapp again.')
        reporting.create_report([
            reporting.Title(title),
            reporting.Summary(summary),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.KERNEL, reporting.Tags.BOOT]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Remediation(hint=remediation),
            reporting.RelatedResource('package', 'kernel')
        ])
Ejemplo n.º 3
0
    def process(self):
        openssh_messages = self.consume(OpenSshConfig)
        config = next(openssh_messages, None)
        if list(openssh_messages):
            api.current_logger().warning(
                'Unexpectedly received more than one OpenSshConfig message.')
        if not config:
            raise StopActorExecutionError(
                'Could not check openssh configuration',
                details={'details': 'No OpenSshConfig facts found.'})

        resources = [
            reporting.RelatedResource('package', 'openssh-server'),
            reporting.RelatedResource('file', '/etc/ssh/sshd_config')
        ]
        if not config.permit_root_login:
            # TODO find out whether the file was modified and will be
            # replaced by the update. If so, this message is bogus
            create_report([
                reporting.Title(
                    'Possible problems with remote login using root account'),
                reporting.Summary(
                    'OpenSSH configuration file does not explicitly state '
                    'the option PermitRootLogin in sshd_config file, '
                    'which will default in RHEL8 to "prohibit-password".'),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags(COMMON_REPORT_TAGS),
                reporting.Remediation(
                    hint='If you depend on remote root logins using '
                    'passwords, consider setting up a different '
                    'user for remote administration or adding '
                    '"PermitRootLogin yes" to sshd_config.'),
                reporting.Flags([reporting.Flags.INHIBITOR])
            ] + resources)

        # Check if there is at least one PermitRootLogin other than "no"
        # in match blocks (other than Match All).
        # This usually means some more complicated setup depending on the
        # default value being globally "yes" and being overwritten by this
        # match block
        if semantics_changes(config):
            create_report([
                reporting.Title('OpenSSH configured to allow root login'),
                reporting.Summary(
                    'OpenSSH is configured to deny root logins in match '
                    'blocks, but not explicitly enabled in global or '
                    '"Match all" context. This update changes the '
                    'default to disable root logins using paswords '
                    'so your server migth get inaccessible.'),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags(COMMON_REPORT_TAGS),
                reporting.Remediation(
                    hint='Consider using different user for administrative '
                    'logins or make sure your configration file '
                    'contains the line "PermitRootLogin yes" '
                    'in global context if desired.'),
                reporting.Flags([reporting.Flags.INHIBITOR])
            ] + resources)
Ejemplo n.º 4
0
    def process(self):
        unsupported_tables = []
        unsupported_ipset_types = []
        list_separator_fmt = '\n    -'
        for facts in self.consume(FirewalldFacts):
            for table in facts.ebtablesTablesInUse:
                if not private.isEbtablesTableSupported(table):
                    unsupported_tables.append(table)
            for ipset_type in facts.ipsetTypesInUse:
                if not private.isIpsetTypeSupportedByNftables(ipset_type):
                    unsupported_ipset_types.append(ipset_type)

        if unsupported_tables:
            format_tuple = (
                list_separator_fmt,
                list_separator_fmt.join(list(set(unsupported_tables))),
            )
            create_report([
                reporting.Title(
                    'Firewalld is using an unsupported ebtables table.'),
                reporting.Summary(
                    'ebtables in RHEL-8 does not support these tables:{}{}'.
                    format(*format_tuple)),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags([
                    reporting.Tags.FIREWALL, reporting.Tags.SECURITY,
                    reporting.Tags.NETWORK
                ]),
                reporting.Flags([reporting.Flags.INHIBITOR]),
                reporting.Remediation(
                    hint=
                    'Remove firewalld direct rules that use these ebtables tables:{}{}'
                    .format(*format_tuple))
            ] + related)

        if unsupported_ipset_types:
            format_tuple = (
                list_separator_fmt,
                list_separator_fmt.join(list(set(unsupported_ipset_types))),
            )
            create_report([
                reporting.Title(
                    'Firewalld is using an unsupported ipset type.'),
                reporting.Summary(
                    'These ipset types are not supported by firewalld\'s nftables backend:{}{}'
                    .format(*format_tuple)),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags([
                    reporting.Tags.FIREWALL, reporting.Tags.SECURITY,
                    reporting.Tags.NETWORK
                ]),
                reporting.Flags([reporting.Flags.INHIBITOR]),
                reporting.Remediation(
                    hint='Remove ipsets of these types from firewalld:{}{}'.
                    format(*format_tuple))
            ] + related)
def generate_report(existing_custom_network_scripts):
    """ Generate reports informing user about possible manual intervention required """

    # Show documentation url if custom network-scripts detected
    title = "custom network-scripts detected"
    summary = (
        "RHEL 9 does not support the legacy network-scripts package that was"
        " deprecated in RHEL 8. Custom network-scripts have been detected.")

    reporting.create_report([
        reporting.Title(title),
        reporting.Summary(summary),
        reporting.Remediation(hint=(
            "Migrate the custom network-scripts to NetworkManager dispatcher"
            " scripts manually before the ugprade. Follow instructions in the"
            " official documentation.")),
        reporting.Severity(reporting.Severity.HIGH),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.Tags([reporting.Tags.NETWORK, reporting.Tags.SERVICES]),
        reporting.ExternalLink(
            title=
            ("Upgrading from RHEL 8 to 9 - migrating custom network-scripts to"
             " NetworkManager dispatcher scripts"),
            url=DOC_URL,
        ),
    ] + [
        reporting.RelatedResource("file", fname)
        for fname in existing_custom_network_scripts
    ])
Ejemplo n.º 6
0
def check_dialogs(inhibit_if_no_userchoice=True):
    results = list(api.consume(DialogModel))
    for dialog in results:
        sections = dialog.answerfile_sections
        summary = (
            'One or more sections in answerfile are missing user choices: {}\n'
            'For more information consult https://leapp.readthedocs.io/en/latest/dialogs.html'
        )
        dialog_resources = [
            reporting.RelatedResource('dialog', s) for s in sections
        ]
        dialogs_remediation = (
            'Please register user choices with leapp answer cli command or by manually editing '
            'the answerfile.')
        # FIXME: Enable more choices once we can do multi-command remediations
        cmd_remediation = [[
            'leapp', 'answer', '--section', "{}={}".format(s, choice)
        ] for s, choices in dialog.answerfile_sections.items()
                           for choice in choices[:1]]
        report_data = [
            reporting.Title('Missing required answers in the answer file'),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Summary(summary.format('\n'.join(sections))),
            reporting.Flags([reporting.Flags.
                             INHIBITOR] if inhibit_if_no_userchoice else []),
            reporting.Remediation(hint=dialogs_remediation,
                                  commands=cmd_remediation),
            reporting.Key(dialog.key)
        ]
        reporting.create_report(report_data + dialog_resources)
Ejemplo n.º 7
0
def _inhibit_on_duplicate_repos(repofiles):
    """
    Inhibit the upgrade if any repoid is defined multiple times.

    When that happens, it not only shows misconfigured system, but then
    we can't get details of all the available repos as well.
    """
    duplicates = repofileutils.get_duplicate_repositories(repofiles).keys()

    if not duplicates:
        return
    list_separator_fmt = '\n    - '
    api.current_logger().warning(
        'The following repoids are defined multiple times:{0}{1}'.format(
            list_separator_fmt, list_separator_fmt.join(duplicates)))

    reporting.create_report([
        reporting.Title('A YUM/DNF repository defined multiple times'),
        reporting.Summary(
            'The following repositories are defined multiple times:{0}{1}'.
            format(list_separator_fmt, list_separator_fmt.join(duplicates))),
        reporting.Severity(reporting.Severity.MEDIUM),
        reporting.Tags([reporting.Tags.REPOSITORY]),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.Remediation(
            hint='Remove the duplicate repository definitions.')
    ])
Ejemplo n.º 8
0
    def process(self):
        rootdir = next(self.consume(RootDirectory), None)
        if not rootdir:
            raise StopActorExecutionError('Cannot check root symlinks',
                                          details={
                                              'Problem':
                                              'Did not receive a message with '
                                              'root subdirectories'
                                          })
        absolute_links = [
            item for item in rootdir.items
            if item.target and os.path.isabs(item.target)
        ]

        if absolute_links:
            commands = [
                ' '.join([
                    'ln', '-snf',
                    os.path.relpath(item.target, '/'),
                    os.path.join('/', item.name)
                ]) for item in absolute_links
            ]
            remediation = [['sh', '-c', ' && '.join(commands)]]
            reporting.create_report([
                reporting.Title(
                    'Upgrade requires links in root directory to be relative'),
                reporting.Summary(
                    'After rebooting, parts of the upgrade process can fail if symbolic links in / '
                    'point to absolute paths.\n'
                    'Please change these links to relative ones.'),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Flags([reporting.Flags.INHIBITOR]),
                reporting.Remediation(commands=remediation)
            ])
Ejemplo n.º 9
0
    def process(self):
        interfaces = next(self.consume(PersistentNetNamesFacts)).interfaces

        if self.single_eth0(interfaces):
            self.disable_persistent_naming()
        elif len(interfaces) > 1 and self.ethX_count(interfaces) > 0:
            create_report([
                reporting.Title('Unsupported network configuration'),
                reporting.Summary(
                    'Detected multiple physical network interfaces where one or more use kernel naming (e.g. eth0). '
                    'Upgrade process can not continue because stability of names can not be guaranteed. '
                    'Please read the article at https://access.redhat.com/solutions/4067471 for more information.'
                ),
                reporting.ExternalLink(
                    title=
                    'How to perform an in-place upgrade to RHEL 8 when using kernel NIC names on RHEL 7',
                    url='https://access.redhat.com/solutions/4067471'),
                reporting.Remediation(
                    hint=
                    'Rename all ethX network interfaces following the attached KB solution article.'
                ),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags([reporting.Tags.NETWORK]),
                reporting.Flags([reporting.Flags.INHIBITOR])
            ])
Ejemplo n.º 10
0
def get_events(pes_json_directory, pes_json_filename):
    """
    Get all the events from the source JSON file exported from PES.

    :return: List of Event tuples, where each event contains event type and input/output pkgs
    """
    try:
        return parse_pes_events(
            fetch.read_or_fetch(pes_json_filename,
                                directory=pes_json_directory,
                                allow_empty=True))
    except (ValueError, KeyError):
        title = 'Missing/Invalid PES data file ({}/{})'.format(
            pes_json_directory, pes_json_filename)
        summary = 'Read documentation at: https://access.redhat.com/articles/3664871 for more information ' \
            'about how to retrieve the files'
        reporting.create_report([
            reporting.Title(title),
            reporting.Summary(summary),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.RelatedResource(
                'file', os.path.join(pes_json_directory, pes_json_filename))
        ])
        raise StopActorExecution()
Ejemplo n.º 11
0
def _inhibit_on_duplicate_repos(repos_raw_stderr):
    """
    Inhibit the upgrade if any repoid is defined multiple times.

    When that happens, it not only shows misconfigured system, but then we can't get details of all the available
    repos as well.
    """
    duplicates = []
    for duplicate in re.findall(
            r'Repository ([^\s]+) is listed more than once', repos_raw_stderr,
            re.DOTALL | re.MULTILINE):
        duplicates.append(duplicate)

    if not duplicates:
        return
    list_separator_fmt = '\n    - '
    api.current_logger().warn(
        'The following repoids are defined multiple times:{0}{1}'.format(
            list_separator_fmt, list_separator_fmt.join(duplicates)))

    reporting.create_report([
        reporting.Title('A YUM/DNF repository defined multiple times'),
        reporting.Summary(
            'The `yum repoinfo` command reports that the following repositories are defined multiple times:{0}{1}'
            .format(list_separator_fmt, list_separator_fmt.join(duplicates))),
        reporting.Severity(reporting.Severity.MEDIUM),
        reporting.Tags([reporting.Tags.REPOSITORY]),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.Remediation(
            hint='Remove the duplicit repository definitions.')
    ])
Ejemplo n.º 12
0
 def process(self):
     if not all(next(self.consume(model), None) for model in self.consumes):
         return
     if self.file_baseurl_in_use():
         warn_msg = (
             "Local repository found (baseurl starts with file:///). "
             "Currently leapp does not support this option.")
         self.log.warning(warn_msg)
         reporting.create_report([
             reporting.Title("Local repository detected"),
             reporting.Summary(warn_msg),
             reporting.Severity(reporting.Severity.HIGH),
             reporting.Tags([reporting.Tags.REPOSITORY]),
             reporting.Flags([reporting.Flags.INHIBITOR]),
             reporting.Remediation(
                 hint=("By using Apache HTTP Server you can expose "
                       "your local repository via http. See the linked "
                       "article for details. ")),
             reporting.ExternalLink(
                 title=("Customizing your Red Hat Enterprise Linux "
                        "in-place upgrade"),
                 url=("https://access.redhat.com/articles/4977891/"
                      "#repos-known-issues"),
             ),
         ])
Ejemplo n.º 13
0
def process():
    if not architecture.matches_architecture(architecture.ARCH_S390X):
        return
    cpuinfo = next(api.consume(CPUInfo), None)
    if cpuinfo is None:
        raise StopActorExecutionError(message=("Missing information about CPU."))

    if not cpuinfo.machine_type:
        # this is not expected to happen, but in case...
        api.curernt_logger().warning("The machine (CPU) type is empty.")

    if cpuinfo.machine_type not in SUPPORTED_MACHINE_TYPES:
        summary = ("The machine is not possible to upgrade because of unsupported"
                   " type of the processor. Regarding the official documentation,"
                   " z13 and z14 processors are supported on the Red Had Enterprise"
                   " Linux 8 system for the IBM Z architecture. If you have one of"
                   " the supported processors, you should see provided the machine"
                   " type in the /proc/cpuinfo file with one of those values: {}."
                   " Detected machine type of the CPU is '{}'."
                   .format(", ".join([str(i) for i in SUPPORTED_MACHINE_TYPES]), cpuinfo.machine_type))
        report = [
            reporting.Title("The processor is not supported by the target system."),
            reporting.Summary(summary),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.ExternalLink(
                title="Considerations in adopting RHEL 8",
                url=("https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/"
                     "html-single/considerations_in_adopting_rhel_8/"
                     "index#changes-in-gcc-in-rhel-8_changes-in-toolchain-since-rhel-7"))
        ]
        reporting.create_report(report)
def process():
    storage = _get_storage_data()
    used_removed_options = set()
    for entry in storage.fstab:
        if entry.fs_vfstype == 'xfs':
            # NOTE: some opts could have a value, like ihashsize=4096 - we want
            # just the name of the option (that's why the double-split)
            options = set([opt.split('=')[0] for opt in entry.fs_mntops.split(',')])
            used_removed_options.update(options.intersection(REMOVED_XFS_OPTIONS))

    if not used_removed_options:
        return

    list_separator_fmt = '\n    - '
    reporting.create_report([
        reporting.Title('Deprecated XFS mount options present in FSTAB.'),
        reporting.Summary(
            'Some XFS mount options are not supported on RHEL 8 and prevent'
            ' system from booting correctly if any of the reported XFS options are used.'
            ' filesystem:{}{}.'.format(
                list_separator_fmt,
                list_separator_fmt.join(list(REMOVED_XFS_OPTIONS)))),
        reporting.Severity(reporting.Severity.HIGH),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.Tags([reporting.Tags.FILESYSTEM]),
        reporting.RelatedResource('file', '/etc/fstab'),
        reporting.Remediation(hint=(
            'Drop the following mount options from the /etc/fstab file for any'
            ' XFS filesystem: {}.'.format(', '.join(used_removed_options)))),
    ])
Ejemplo n.º 15
0
 def process(self):
     try:
         quagga_facts = next(self.consume(QuaggaToFrrFacts))
     except StopIteration:
         return
     if 'babeld' in quagga_facts.active_daemons or 'babeld' in quagga_facts.enabled_daemons:
         create_report([
             reporting.Title('Babeld is not available in FRR'),
             reporting.ExternalLink(
                 url='https://access.redhat.com/'
                 'documentation/en-us/red_hat_enterprise_linux/8/html/'
                 'configuring_and_managing_networking/setting-your-rou'
                 'ting-protocols_configuring-and-managing-networking',
                 title='Setting routing protocols in RHEL8'),
             reporting.Summary(
                 'babeld daemon which was a part of quagga implementation in RHEL7 '
                 'is not available in RHEL8 in FRR due to licensing issues.'
             ),
             reporting.Severity(reporting.Severity.HIGH),
             reporting.Tags(COMMON_REPORT_TAGS),
             reporting.Flags([reporting.Flags.INHIBITOR]),
             reporting.Remediation(
                 hint='Please use RIP, OSPF or EIGRP instead of Babel')
         ])
     else:
         self.log.debug('babeld not used, moving on.')
Ejemplo n.º 16
0
    def process(self):

        hint = 'In order to unload the module from the running system, check the accompanied command.'
        command = ['modprobe', '-r', 'btrfs']

        for fact in self.consume(ActiveKernelModulesFacts):
            for active_module in fact.kernel_modules:
                if active_module.filename == 'btrfs':
                    create_report([
                        reporting.Title('Btrfs has been removed from RHEL8'),
                        reporting.Summary(
                            'The Btrfs file system was introduced as Technology Preview with the '
                            'initial release of Red Hat Enterprise Linux 6 and Red Hat Enterprise Linux 7. As of '
                            'versions 6.6 and 7.4 this technology has been deprecated and removed in RHEL8.'
                        ),
                        reporting.ExternalLink(
                            title='Considerations in adopting RHEL 8 - btrfs has been removed.',
                            url='https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/considerations_in_adopting_rhel_8/file-systems-and-storage_considerations-in-adopting-rhel-8#btrfs-has-been-removed_file-systems-and-storage'  # noqa: E501; pylint: disable=line-too-long
                        ),
                        reporting.ExternalLink(
                            title='How do I prevent a kernel module from loading automatically?',
                            url='https://access.redhat.com/solutions/41278'
                        ),
                        reporting.Severity(reporting.Severity.HIGH),
                        reporting.Flags([reporting.Flags.INHIBITOR]),
                        reporting.Tags([reporting.Tags.FILESYSTEM]),
                        reporting.Remediation(hint=hint, commands=[command]),
                        reporting.RelatedResource('kernel-driver', 'btrfs')
                    ])
                    break
Ejemplo n.º 17
0
    def process(self):
        removed_file = 'files/removed_drivers.txt'
        conflicting = check_drivers(get_removed_drivers(removed_file),
                                    get_present_drivers())

        if conflicting:
            title = ('Detected loaded kernel drivers which have been removed '
                     'in RHEL 8. Upgrade cannot proceed.')
            URL = (
                'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/'
                'considerations_in_adopting_rhel_8/index#removed-device-drivers_hardware-enablement'
            )
            summary = ('Support for the following RHEL 7 '
                       'device drivers has been removed in RHEL 8: \n     - {}'
                       '\nPlease see {} for details.'.format(
                           '\n     - '.join(conflicting), URL))
            remediation = (
                'Please disable detected kernel drivers in '
                'order to proceed with the upgrade process using the rmmod or modprobe -r.'
            )
            create_report([
                reporting.Title(title),
                reporting.Summary(summary),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags([reporting.Tags.KERNEL, reporting.Tags.DRIVERS
                                ]),
                reporting.Flags([reporting.Flags.INHIBITOR]),
                reporting.Remediation(hint=remediation)
            ] + [
                reporting.RelatedResource('kernel-driver', kd)
                for kd in conflicting
            ])
Ejemplo n.º 18
0
    def process(self):
        tftp_client_service = 'tftp-client'
        send_report = False

        for facts in self.consume(FirewalldUsedObjectNames):
            if tftp_client_service in facts.services:
                send_report = True

        if send_report:
            create_report([
                reporting.Title('Unsupported Firewalld Configuration In Use'),
                reporting.Summary(
                    'Firewalld has service "{service}" enabled. '
                    'Service "{service}" has been removed in RHEL-9.'.format(
                        service=tftp_client_service)),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags(
                    [reporting.Tags.SANITY, reporting.Tags.FIREWALL]),
                reporting.Flags([reporting.Flags.INHIBITOR]),
                reporting.Remediation(hint=(
                    'Remove all usage of service "{service}" from '
                    'firewalld\'s permanent configuration. '
                    'It may be in use by: zones, policies, or rich rules.\n'
                    'Usage can be found by listing zone and policy '
                    'configuration:\n'
                    '  # firewall-cmd --permanent --list-all-zones\n'
                    '  # firewall-cmd --permanent --list-all-policies\n'
                    'Example to remove usage from a zone:\n'
                    '  # firewall-cmd --permanent --zone public '
                    ' --remove-service {service}\n'.format(
                        service=tftp_client_service))),
            ])
Ejemplo n.º 19
0
def _report_excluded_repos(repos):
    api.current_logger().info(
        "The optional repository is not enabled. Excluding %r "
        "from the upgrade",
        repos,
    )

    report = [
        reporting.Title("Excluded RHEL 8 repositories"),
        reporting.Summary(
            "The following repositories are not supported by "
            "Red Hat and are excluded from the list of repositories "
            "used during the upgrade.\n- {}".format("\n- ".join(repos))
        ),
        reporting.Severity(reporting.Severity.INFO),
        reporting.Tags([reporting.Tags.REPOSITORY]),
        reporting.Flags([reporting.Flags.FAILURE]),
        reporting.Remediation(
            hint=(
                "If you still require to use the excluded repositories "
                "during the upgrade, execute leapp with the following options: {}."
            ).format(" ".join(["--enablerepo {}".format(repo) for repo in repos])),
        ),
    ]
    reporting.create_report(report)
Ejemplo n.º 20
0
    def process(self):
        if not architecture.matches_architecture(architecture.ARCH_S390X):
            return

        cmdline = library.get_kernel_cmdline()
        if library.znet_is_set(cmdline):
            _report = [
                reporting.Title(
                    'Detected the rd.znet parameter in kernel cmdline'),
                reporting.Severity(reporting.Severity.HIGH),
                reporting.Tags(([reporting.Tags.SANITY])),
                reporting.Flags(([reporting.Flags.INHIBITOR])),
                reporting.Summary(
                    'Upgrade on s390x machines with the rd.znet kernel'
                    ' parameter is not supported and the upgrade has been'
                    ' inhibited.')
            ]

            if not library.vlan_is_used():
                hint = (
                    'If you want to continue, remove the rd.znet parameter from'
                    ' the kernel cmdline using grubby and zipl tools and reboot.'
                    ' But only in case you are sure you do not the parameter'
                    ' specified to have working network. E.g. in case you are'
                    ' using VLAN, you should not do that.')
                _report.append(reporting.Remediation(hint=hint))
            reporting.create_report(_report)
Ejemplo n.º 21
0
def inhibit(node_type):
    create_report([
        reporting.Title("Use of HA cluster detected. Upgrade can't proceed."),
        reporting.Summary(
            "HA cluster is not supported by the inplace upgrade.\n"
            "HA cluster configuration file(s) found."
            " It seems to be a cluster {0}.".format(node_type)),
        reporting.Severity(reporting.Severity.HIGH),
        reporting.Tags([reporting.Tags.HIGH_AVAILABILITY]),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.ExternalLink(
            url="https://access.redhat.com/articles/2059253",
            title=(
                "Recommended Practices for Applying Software Updates"
                " to a RHEL High Availability or Resilient Storage Cluster"),
        ),
        reporting.Remediation(
            hint=(
                "Destroy the existing HA cluster"
                " or (if you have already removed HA cluster packages) remove"
                " configuration files {0} and {1}".format(
                    CIB_LOCATION,
                    COROSYNC_CONF_LOCATION,
                )),
            commands=[[
                "sh", "-c",
                "pcs cluster stop --all --wait && pcs cluster destroy --all"
            ]]),
        reporting.RelatedResource('file', COROSYNC_CONF_LOCATION),
        reporting.RelatedResource('file', CIB_LOCATION)
    ])
Ejemplo n.º 22
0
def process():
    if not architecture.matches_architecture(architecture.ARCH_S390X):
        return

    pkgs = _get_kernel_rpms()
    if not pkgs:
        # Hypothatical, user is not allowed to install any kernel that is not signed by RH
        # In case we would like to be cautious, we could check whether there are no other
        # kernels installed as well.
        api.current_logger().log.error(
            'Cannot find any installed kernel signed by Red Hat.')
        raise StopActorExecutionError(
            'Cannot find any installed kernel signed by Red Hat.')
    if len(pkgs) > 1:
        # It's temporary solution, so no need to try automatize everything.
        title = 'Multiple kernels installed'
        summary = (
            'The upgrade process does not handle well the case when multiple kernels'
            ' are installed on s390x. There is a severe risk of the bootloader configuration'
            ' getting corrupted during the upgrade.')
        remediation = (
            'Boot into the most up-to-date kernel and remove all older'
            ' kernels installed on the machine before running Leapp again.')
        reporting.create_report([
            reporting.Title(title),
            reporting.Summary(summary),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.KERNEL, reporting.Tags.BOOT]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Remediation(hint=remediation),
            reporting.RelatedResource('package', 'kernel')
        ])
def process():
    # blacklist CRB repo if optional repo is not enabled
    reposid_blacklist = _get_disabled_optional_repo()
    if reposid_blacklist:
        api.current_logger().info(
            "The optional repository is not enabled. Blacklisting the CRB repository."
        )
        api.produce(RepositoriesBlacklisted(repoids=reposid_blacklist))

        report = [
            reporting.Title("Excluded RHEL 8 repositories"),
            reporting.Summary(
                "The following repositories are not supported by "
                "Red Hat and are excluded from the list of repositories "
                "used during the upgrade.\n- {}".format(
                    "\n- ".join(reposid_blacklist))),
            reporting.Severity(reporting.Severity.INFO),
            reporting.Tags([reporting.Tags.REPOSITORY]),
            reporting.Flags([reporting.Flags.FAILURE]),
            reporting.ExternalLink(
                url=("https://access.redhat.com/documentation/en-us/"
                     "red_hat_enterprise_linux/8/html/package_manifest/"
                     "codereadylinuxbuilder-repository."),
                title="CodeReady Linux Builder repository",
            ),
        ]
        reporting.create_report(report)
Ejemplo n.º 24
0
def version2_check(info):
    """ Performs all checks for SAP HANA 2 and creates a report if anything unsupported has been detected """
    found = {}
    for instance in info.instances:
        if _manifest_get(instance.manifest, 'release', None) == '1.00':
            continue
        if not _fullfills_hana_min_version(instance):
            _add_hana_details(found, instance)

    if found:
        detected = _create_detected_instances_list(found)
        reporting.create_report([
            reporting.Title('SAP HANA needs to be updated before upgrade'),
            reporting.Summary((
                'A newer version of SAP HANA is required in order continue with the upgrade.'
                ' {min_hana_version} is required for the target version of RHEL.\n\n'
                'The following SAP HANA instances have been detected to be running with a lower version'
                ' than required on the target system:\n'
                '{detected}').format(
                    detected=detected,
                    min_hana_version=SAP_HANA_MINIMAL_VERSION_STRING)),
            reporting.RemediationHint('Update SAP HANA at least to {}'.format(
                SAP_HANA_MINIMAL_VERSION_STRING)),
            reporting.ExternalLink(
                url='https://launchpad.support.sap.com/#/notes/2235581',
                title='SAP HANA: Supported Operating Systems'),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Audience('sysadmin')
        ])
Ejemplo n.º 25
0
def version1_check(info):
    """ Creates a report for SAP HANA instances running on version 1 """
    found = {}
    for instance in info.instances:
        if _manifest_get(instance.manifest, 'release') == '1.00':
            _add_hana_details(found, instance)

    if found:
        detected = _create_detected_instances_list(found)
        reporting.create_report([
            reporting.Title(
                'Found SAP HANA 1 which is not supported with the target version of RHEL'
            ),
            reporting.Summary((
                'SAP HANA 1.00 is not supported with the version of RHEL you are upgrading to.\n\n'
                'The following instances have been detected to be version 1.00:\n'
                '{}'.format(detected))),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.RemediationHint((
                'In order to upgrade RHEL, you will have to upgrade your SAP HANA 1.0 software to '
                '{supported}.'.format(
                    supported=SAP_HANA_MINIMAL_VERSION_STRING))),
            reporting.ExternalLink(
                url='https://launchpad.support.sap.com/#/notes/2235581',
                title='SAP HANA: Supported Operating Systems'),
            reporting.Tags([reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.Audience('sysadmin')
        ])
Ejemplo n.º 26
0
def _check_default_path_checker(options):
    if not options['default_path_checker']:
        return
    value, pathname = options['default_path_checker']
    if value == 'tur':
        return
    create_report([
        reporting.Title('Unsupported device-mapper-multipath configuration'),
        reporting.Summary(
            'device-mapper-multipath has changed the default path_checker '
            'from "directio" to "tur" in RHEL-8. Further, changing the '
            'default path_checker can cause issues with built-in device '
            'configurations in RHEL-8. Please remove the "path_checker" '
            'option from the defaults section of {}, and add it to the '
            'device configuration of any devices that need it.'.format(
                pathname)),
        reporting.Severity(reporting.Severity.HIGH),
        reporting.Tags([reporting.Tags.SERVICES]),
        reporting.Flags([reporting.Flags.INHIBITOR]),
        reporting.RelatedResource('package', 'device-mapper-multipath'),
        reporting.RelatedResource('file', pathname),
        reporting.Remediation(
            hint='Please remove the "path_checker {}" option from the '
            'defaults section of {}, and add it to the device configuration '
            'of any devices that need it.'.format(value, pathname))
    ])
Ejemplo n.º 27
0
def get_os_release(path):
    """Retrieve data about System OS release from provided file."""
    try:
        with open(path) as f:
            data = dict(l.strip().split('=', 1) for l in f.readlines()
                        if '=' in l)
            return OSRelease(release_id=data.get('ID', '').strip('"'),
                             name=data.get('NAME', '').strip('"'),
                             pretty_name=data.get('PRETTY_NAME',
                                                  '').strip('"'),
                             version=data.get('VERSION', '').strip('"'),
                             version_id=data.get('VERSION_ID', '').strip('"'),
                             variant=data.get('VARIANT', '').strip('"')
                             or None,
                             variant_id=data.get('VARIANT_ID', '').strip('"')
                             or None)
    except IOError as e:
        reporting.create_report([
            reporting.Title('Error while collecting system OS facts'),
            reporting.Summary(str(e)),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Tags([reporting.Tags.OS_FACTS, reporting.Tags.SANITY]),
            reporting.Flags([reporting.Flags.INHIBITOR]),
            reporting.RelatedResource('file', path)
        ])
        return None
Ejemplo n.º 28
0
    def process(self):
        for decision in self.consume(SelinuxRelabelDecision):
            if decision.set_relabel:
                try:
                    with open('/.autorelabel', 'w'):
                        pass
                    create_report([
                        reporting.Title('SElinux scheduled for relabelling'),
                        reporting.Summary(
                            '/.autorelabel file touched on root in order to schedule SElinux relabelling.'
                        ),
                        reporting.Severity(reporting.Severity.INFO),
                        reporting.Tags(COMMON_REPORT_TAGS),
                    ] + related)

                except EnvironmentError as e:
                    # FIXME: add an "action required" flag later
                    create_report([
                        reporting.Title(
                            'Could not schedule SElinux for relabelling'),
                        reporting.Summary(
                            '/.autorelabel file could not be created: {}.'.
                            format(e)),
                        reporting.Severity(reporting.Severity.HIGH),
                        reporting.Tags(COMMON_REPORT_TAGS),
                        reporting.Remediation(
                            hint=
                            'Please set autorelabelling manually after the upgrade.'
                        ),
                        reporting.Flags([reporting.Flags.FAILURE])
                    ] + related)
                    self.log.critical(
                        'Could not schedule SElinux for relabelling: %s.' % e)
Ejemplo n.º 29
0
    def process(self):
        with open('files/removed_drivers.txt', 'r') as removed:
            removed_drivers = []
            whitelisted_modules = set()
            collected_drivers = set()

            # Extracting kernel drivers from the files/removed_drivers.txt.
            for line in removed.readlines():
                token = line.strip()
                if token.startswith('#') or not token:
                    # We do not want comments or empty lines.
                    continue
                removed_drivers.append(token)

            # Consuming whitelisted kernel modules.
            for fact in self.consume(WhitelistedKernelModules):
                whitelisted_modules.update(fact.whitelisted_modules)

            # Collecting only non-whitelisted drivers that are part of the
            # files/removed_drivers.txt.
            for fact in self.consume(ActiveKernelModulesFacts):
                for active_module in fact.kernel_modules:
                    if active_module.filename in whitelisted_modules:
                        continue
                    if active_module.filename in removed_drivers:
                        collected_drivers.add(active_module.filename)

            # In the end, we are only going to report drivers that are:
            # - removed in the RHEL8 (are part of files/removed_drivers.txt)
            # - not whitelisted
            if collected_drivers:
                title = (
                    'Detected loaded kernel drivers which have been removed '
                    'in RHEL 8. Upgrade cannot proceed.')
                URL = (
                    'https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/'
                    'considerations_in_adopting_rhel_8/index#removed-device-drivers_hardware-enablement'
                )
                summary = (
                    'Support for the following RHEL 7 '
                    'device drivers has been removed in RHEL 8: \n     - {}'
                    '\nPlease see {} for details.'.format(
                        '\n     - '.join(collected_drivers), URL))
                remediation = (
                    'Please disable detected kernel drivers in '
                    'order to proceed with the upgrade process using the rmmod or modprobe -r.'
                )
                create_report([
                    reporting.Title(title),
                    reporting.Summary(summary),
                    reporting.Severity(reporting.Severity.HIGH),
                    reporting.Tags(
                        [reporting.Tags.KERNEL, reporting.Tags.DRIVERS]),
                    reporting.Flags([reporting.Flags.INHIBITOR]),
                    reporting.Remediation(hint=remediation)
                ] + [
                    reporting.RelatedResource('kernel-driver', km)
                    for km in collected_drivers
                ])
Ejemplo n.º 30
0
def _get_fstab_info(fstab_path):
    """ Collect storage info from /etc/fstab file """
    if _is_file_readable(fstab_path):
        with open(fstab_path, 'r') as fstab:
            for line, entry in enumerate(fstab, 1):
                if entry.startswith('#'):
                    continue

                entry = entry.strip()
                if not entry:
                    continue

                entries = entry.split()

                if len(entries) == 4:
                    entries.append('0')

                if len(entries) == 5:
                    entries.append('0')

                if len(entries) != 6:
                    if any(value.startswith('#') for value in entries):
                        remediation = (
                            'Comments in the /etc/fstab file must be at the beginning of the line, your file has a'
                            ' comment at the end of the line at line {}, please edit and fix this, for further'
                            ' information read fstab man page (man 5 fstab).'.format(line)
                        )
                    else:
                        remediation = (
                            'The /etc/fstab file must have at least 4 values and at most 6 per line, your file on the'
                            ' line: {} have {} values, please edit and fix this, for further information read'
                            ' fstab man page (man 5 fstab). '.format(line, len(entries))
                        )
                    summary = (
                        'The fstab configuration file seems to be invalid. You need to fix it to be able to proceed'
                        ' with the upgrade process.'
                    )
                    reporting.create_report([
                        reporting.Title('Problems with parsing data in /etc/fstab'),
                        reporting.Summary(summary),
                        reporting.Severity(reporting.Severity.HIGH),
                        reporting.Tags([reporting.Tags.FILESYSTEM]),
                        reporting.Flags([reporting.Flags.INHIBITOR]),
                        reporting.Remediation(hint=remediation),
                        reporting.RelatedResource('file', '/etc/fstab')
                    ])

                    api.current_logger().error(summary)
                    break

                fs_spec, fs_file, fs_vfstype, fs_mntops, fs_freq, fs_passno = entries
                yield FstabEntry(
                    fs_spec=fs_spec,
                    fs_file=fs_file,
                    fs_vfstype=fs_vfstype,
                    fs_mntops=fs_mntops,
                    fs_freq=fs_freq,
                    fs_passno=fs_passno)