Exemple #1
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)
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')
        ])
Exemple #3
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)
Exemple #4
0
 def process(self):
     if has_package(InstalledRedHatSignedRPM, 'grep'):
         create_report([
             reporting.Title(
                 'Grep has incompatible changes in the next major version'),
             reporting.Summary(
                 'If a file contains data improperly encoded for the current locale, and this is '
                 'discovered before any of the file\'s contents are output, grep now treats the file '
                 'as binary.\n'
                 'The \'grep -P\' no longer reports an error and exits when given invalid UTF-8 data. '
                 'Instead, it considers the data to be non-matching.\n'
                 'In locales with multibyte character encodings other than UTF-8, grep -P now reports '
                 'an error and exits instead of misbehaving.\n'
                 'When searching binary data, grep now may treat non-text bytes as line terminators. '
                 'This can boost performance significantly.\n'
                 'The \'grep -z\' no longer automatically treats the byte \'\\200\' as binary data.\n'
                 'Context no longer excludes selected lines omitted because of -m. For example, '
                 '\'grep "^" -m1 -A1\' now outputs the first two input lines, not just the first '
                 'line.\n'),
             reporting.Severity(reporting.Severity.LOW),
             reporting.Tags([reporting.Tags.TOOLS]),
             reporting.Remediation(
                 hint=
                 'Please update your scripts to be compatible with the changes.'
             ),
             reporting.RelatedResource('package', 'grep')
         ])
Exemple #5
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)
            ])
def update_grub_core(grub_dev):
    """
    Update GRUB core after upgrade from RHEL7 to RHEL8

    On legacy systems, GRUB core does not get automatically updated when GRUB packages
    are updated.
    """
    cmd = ['grub2-install', grub_dev]
    if config.is_debug():
        cmd += ['-v']
    try:
        run(cmd)
    except CalledProcessError as err:
        reporting.create_report([
            reporting.Title('GRUB core update failed'),
            reporting.Summary(str(err)),
            reporting.Tags([reporting.Tags.BOOT]),
            reporting.Severity(reporting.Severity.HIGH),
            reporting.Remediation(
                hint=
                'Please run "grub2-install <GRUB_DEVICE>" manually after upgrade'
            )
        ])
        api.current_logger().warning(
            'GRUB core update on {} failed'.format(grub_dev))
        raise StopActorExecution()
    reporting.create_report([
        reporting.Title('GRUB core successfully updated'),
        reporting.Summary(
            'GRUB core on {} was successfully updated'.format(grub_dev)),
        reporting.Tags([reporting.Tags.BOOT]),
        reporting.Severity(reporting.Severity.INFO)
    ])
Exemple #7
0
    def process(self):
        if architecture.matches_architecture(architecture.ARCH_S390X):
            # s390x archs use ZIPL instead of GRUB
            return

        ff = next(self.consume(FirmwareFacts), None)
        if ff and ff.firmware == 'bios':
            dev = next(self.consume(GrubDevice), None)
            if dev:
                self.produce(UpdateGrub(grub_device=dev.grub_device))
                create_report([
                    reporting.Title(
                        'GRUB core will be updated during upgrade'),
                    reporting.Summary(GRUB_SUMMARY),
                    reporting.Severity(reporting.Severity.HIGH),
                    reporting.Tags([reporting.Tags.BOOT]),
                ])
            else:
                create_report([
                    reporting.Title(
                        'Leapp could not identify where GRUB core is located'),
                    reporting.Summary(
                        'We assume GRUB core is located on the same device as /boot. Leapp needs to '
                        'update GRUB core as it is not done automatically on legacy (BIOS) systems. '
                    ),
                    reporting.Severity(reporting.Severity.HIGH),
                    reporting.Tags([reporting.Tags.BOOT]),
                    reporting.Remediation(
                        hint=
                        'Please run "grub2-install <GRUB_DEVICE> command manually after upgrade'
                    ),
                ])
Exemple #8
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])
            ])
Exemple #9
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
            ])
Exemple #10
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)
Exemple #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.')
    ])
Exemple #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"),
             ),
         ])
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)))),
    ])
Exemple #14
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.')
Exemple #15
0
    def process(self):
        model = next(self.consume(SSSDConfig8to9), None)
        if not model:
            return

        # enable_files_domain is set explicitly, change of default has no effect
        if model.enable_files_domain_set:
            return

        # there is explicit files domain, implicit files domain has no effect
        if model.explicit_files_domain:
            return

        # smartcard authentication is disabled, implicit files domain has no effect
        if not model.pam_cert_auth:
            return

        create_report([
            reporting.Title('SSSD implicit files domain is now disabled by default.'),
            reporting.Summary('Default value of [sssd]/enable_files_domain has '
                              'changed from true to false.'),
            reporting.Tags(COMMON_REPORT_TAGS),
            reporting.Remediation(
                hint='If you use smartcard authentication for local users, '
                     'set this option to true explicitly and call '
                     '"authselect enable-feature with-files-domain".'
            ),
            reporting.Severity(reporting.Severity.MEDIUM)
        ] + related)
Exemple #16
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))),
            ])
Exemple #17
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)
Exemple #18
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)
Exemple #19
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
Exemple #20
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.')
    ])
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)
    ])
Exemple #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 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
    ])
Exemple #24
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)
Exemple #25
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))
    ])
def report_skipped_packages(title,
                            message,
                            package_repo_pairs,
                            remediation=None):
    """Generate report message about skipped packages"""
    package_repo_pairs = sorted(package_repo_pairs)
    summary = '{} {}\n{}'.format(
        len(package_repo_pairs), message, '\n'.join([
            '- {pkg} (repoid: {repo})'.format(pkg=pkg, repo=repo)
            for pkg, repo in package_repo_pairs
        ]))
    report_content = [
        reporting.Title(title),
        reporting.Summary(summary),
        reporting.Severity(reporting.Severity.HIGH),
        reporting.Tags([reporting.Tags.REPOSITORY]),
    ]
    if remediation:
        report_content += [reporting.Remediation(hint=remediation)]
    report_content += [
        reporting.RelatedResource('package', p) for p, _ in package_repo_pairs
    ]
    reporting.create_report(report_content)
    if is_verbose():
        api.current_logger().info(summary)
Exemple #27
0
def ipa_warn_pkg_installed(ipainfo):
    """
    Warn that unused ipa-server package is installed
    """
    if ipainfo.is_client_configured:
        summary = (
            "The ipa-server package is installed but only IdM client is "
            "configured on this system.")
    else:
        summary = (
            "The ipa-server package is installed but neither IdM server "
            "nor client is configured on this system.")
    entries = [
        reporting.Title(
            "ipa-server package is installed but no IdM is configured"),
        reporting.Summary(summary),
        reporting.Remediation(
            hint="Remove unused ipa-server package",
            commands=[["yum", "remove", "-y", "ipa-server"]],
        ),
        reporting.ExternalLink(
            url=MIGRATION_GUIDES[get_source_major_version()],
            title="Migrating IdM from RHEL 7 to 8",
        ),
        reporting.Severity(reporting.Severity.MEDIUM),
        reporting.Tags([reporting.Tags.SERVICES]),
        reporting.RelatedResource("package", "ipa-server"),
    ]
    return reporting.create_report(entries)
Exemple #28
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
                ])
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)
Exemple #30
0
 def process(self):
     arch = self.configuration.architecture
     for provider, info in rhui.RHUI_CLOUD_MAP[arch].items():
         if has_package(InstalledRPM, info['el7_pkg']):
             if not rhsm.skip_rhsm():
                 create_report([
                     reporting.Title(
                         'Upgrade initiated with RHSM on public cloud with RHUI infrastructure'
                     ),
                     reporting.Summary(
                         'Leapp detected this system is on public cloud with RHUI infrastructure '
                         'but the process was initiated without "--no-rhsm" command line option '
                         'which implies RHSM usage (valid subscription is needed).'
                     ),
                     reporting.Severity(reporting.Severity.INFO),
                     reporting.Tags([reporting.Tags.PUBLIC_CLOUD]),
                 ])
                 return
             # AWS RHUI package is provided and signed by RH but the Azure one not
             if not has_package(InstalledRPM, info['leapp_pkg']):
                 create_report([
                     reporting.Title('Package "{}" is missing'.format(
                         info['leapp_pkg'])),
                     reporting.Summary(
                         'On {} using RHUI infrastructure, a package "{}" is needed for'
                         'in-place upgrade'.format(provider.upper(),
                                                   info['leapp_pkg'])),
                     reporting.Severity(reporting.Severity.HIGH),
                     reporting.RelatedResource('package',
                                               info['leapp_pkg']),
                     reporting.Flags([reporting.Flags.INHIBITOR]),
                     reporting.Tags(
                         [reporting.Tags.PUBLIC_CLOUD,
                          reporting.Tags.RHUI]),
                     reporting.Remediation(commands=[[
                         'yum', 'install', '-y', info['leapp_pkg']
                     ]])
                 ])
                 return
             if provider == 'aws':
                 # We have to disable Amazon-id plugin in the initramdisk phase as the network
                 # is down at the time
                 self.produce(
                     DNFPluginTask(name='amazon-id',
                                   disable_in=['upgrade']))
             # if RHEL7 and RHEL8 packages differ, we cannot rely on simply updating them
             if info['el7_pkg'] != info['el8_pkg']:
                 self.produce(
                     RpmTransactionTasks(to_install=[info['el8_pkg']]))
                 self.produce(
                     RpmTransactionTasks(to_remove=[info['el7_pkg']]))
             self.produce(RHUIInfo(provider=provider))
             self.produce(
                 RequiredTargetUserspacePackages(
                     packages=[info['el8_pkg']]))
             return