예제 #1
0
def is_sysconfig_default():
    """Check if the memcached sysconfig file was not modified since installation."""
    try:
        result = run(['rpm', '-V', '--nomtime', 'memcached'], checked=False)
        return sysconfig_path not in result['stdout']
    except OSError as e:
        api.current_logger().warn("rpm verification failed: %s", str(e))
        return True
예제 #2
0
def enable_rhsm_repos():
    """
    Try enabling all the RHEL 8 repositories that have been used for the upgrade transaction.

    In case of custom repositories, the subscription-manager reports an error that it doesn't know them, but it enables
    the known repositories.
    """
    if rhsm.skip_rhsm():
        api.current_logger().debug('Skipping enabling repositories through subscription-manager due to the use of'
                                   ' LEAPP_DEVEL_SKIP_RHSM.')
        return
    try:
        run(get_submgr_cmd(get_repos_to_enable()))
    except CalledProcessError as err:
        api.current_logger().warning('The subscription-manager could not enable some repositories.\n'
                                     'It is expected behavior in case of custom repositories unknown to'
                                     ' the subscription-manager - these need to be enabled manually.\n{0}'
                                     .format(str(err)))
예제 #3
0
def call_with_oserror_handled(cmd):
    """
    Perform run with already handled OSError for some convenience.
    """
    try:
        run(cmd)
    except OSError as e:
        if cmd:
            raise StopActorExecutionError(
                message=str(e),
                details={
                    'hint': 'Please ensure that {} is installed and executable.'.format(cmd[0])
                }
            )
        else:
            raise StopActorExecutionError(
                message='Failed to execute command {} with: {}'.format(''.join(cmd), str(e))
            )
예제 #4
0
def get_booted_kernel():
    """Get version and release of the currently used kernel in one string."""
    try:
        return run(['/usr/bin/uname', '-r'])['stdout'].strip()
    except CalledProcessError as e:
        raise StopActorExecutionError(
            message='Unable to obtain release of the booted kernel.',
            details={'details': str(e), 'stderr': e.stderr}
        )
예제 #5
0
def test_no_encoding():
    """
    Test the output is base64 encoded after getting binary data

    :return: Pass/Fail
    """
    cmd = ['echo', '-n', '-e', '\\xeb']
    result = run(cmd, encoding=None)
    assert isinstance(result['stdout'], six.binary_type)
예제 #6
0
def scan_pci_devices(producer):
    ''' Scan system PCI Devices '''
    try:
        output = run(['lspci', '-mm'], split=True)['stdout']
    except CalledProcessError:
        output = []

    devices = parse_pci_devices(output)
    produce_pci_devices(producer, devices)
예제 #7
0
 def get_rhel8_kernel_version(self):
     kernels = run(["rpm", "-q", "kernel"], split=True)["stdout"]
     for kernel in kernels:
         version = kernel.split("-", 1)[1]
         if "el8" in version:
             return version
     raise StopActorExecutionError(
         "Cannot get version of the installed RHEL-8 kernel",
         details={"details": "\n".join(kernels)})
def _run_cmd(cmd, logmsg="", split=False):
    try:
        return run(cmd, split=split).get("stdout", "")
    except CalledProcessError as e:
        # Only report issues when they are explicitly described.
        # This way expected failures are not reported.
        if logmsg:
            api.current_logger().warning("%s: %s", logmsg, str(e.stderr))
    return None
예제 #9
0
def test_stdin_fd():
    r, w = os.pipe()
    # The string we write here should not exceed `/proc/sys/fs/pipe-max-size`
    # which represents the size of the kernel buffer backing the pipe
    os.write(w, b'LOREM IPSUM')
    os.close(w)
    ret = run(('bash', '-c', 'read MSG; echo "<$MSG>"'), stdin=r)
    os.close(r)
    assert ret['stdout'] == '<LOREM IPSUM>\n'
예제 #10
0
def process():
    kernel_version = next(api.consume(InstalledTargetKernelVersion), None)
    if kernel_version:
        for arg in api.consume(KernelCmdlineArg):
            cmd = ['grubby', '--update-kernel=/boot/vmlinuz-{}'.format(kernel_version.version),
                   '--args={}={}'.format(arg.key, arg.value)]
            try:
                stdlib.run(cmd)
                if architecture.matches_architecture(architecture.ARCH_S390X):
                    # on s390x we need to call zipl explicitly because of issue in grubby,
                    # otherwise the entry is not updated in the ZIPL bootloader
                    # See https://bugzilla.redhat.com/show_bug.cgi?id=1764306
                    stdlib.run(['/usr/sbin/zipl'])

            except (OSError, stdlib.CalledProcessError) as e:
                raise StopActorExecutionError(
                    "Failed to append extra arguments to kernel command line.",
                    details={"details": str(e)})
예제 #11
0
    def _get_firewall_status(service_name):
        try:
            ret_list = run(['systemctl', 'is-active', service_name], split=True)['stdout']
            active = ret_list[0] == 'active'
        except CalledProcessError:
            active = False
            logger.debug('The %s service is likely not active' % service_name)

        try:
            ret_list = run(['systemctl', 'is-enabled', service_name], split=True)['stdout']
            enabled = ret_list[0] == 'enabled'
        except CalledProcessError:
            enabled = False
            logger.debug('The %s service is likely not enabled nor running' % service_name)

        return FirewallStatus(
            active=active,
            enabled=enabled,
            )
예제 #12
0
    def process(self):
        service_name = 'leapp_resume.service'
        if os.path.isfile('/etc/systemd/system/{}'.format(service_name)):
            run(['systemctl', 'disable', service_name])
            try:
                os.unlink('/etc/systemd/system/{}'.format(service_name))
                os.unlink('/etc/systemd/system/default.target.wants/{}'.format(
                    service_name))
            except OSError as e:
                if e.errno != errno.ENOENT:
                    raise

        create_report([
            reporting.Title('"{}" service deleted'.format(service_name)),
            reporting.Summary(
                '"{}" was taking care of resuming upgrade process '
                'after the first reboot.'.format(service_name)),
            reporting.Tags([reporting.Tags.UPGRADE_PROCESS]),
        ])
예제 #13
0
def read_rpm_modifications():
    """Asks RPM database whether the configuration file was modified."""

    try:
        return run(['rpm', '-Vf', CONFIG], split=True, checked=False)['stdout']
    except OSError as err:
        error = 'Failed to check the modification status of the {}: {}' \
                ''.format(CONFIG, str(err))
        api.current_logger().error(error)
        return []
예제 #14
0
 def unit_enabled(self, name):
     try:
         ret = run(['systemctl', 'is-enabled', name], split=True)['stdout']
         if len(ret) > 0:
             enabled = ret[0] == 'enabled'
         else:
             enabled = False
     except (OSError, CalledProcessError):
         enabled = False
     return enabled
예제 #15
0
 def process(self):
     cmdline = run(['cat', '/proc/cmdline'])['stdout'].strip()
     parameters = []
     for parameter in cmdline.split(' '):
         if '=' in parameter:
             kv = parameter.split('=')
             parameters.append(KernelCmdlineArg(key=kv[0], value=kv[1]))
         else:
             parameters.append(KernelCmdlineArg(key=parameter))
     self.produce(KernelCmdline(parameters=parameters))
예제 #16
0
def remove_custom_modules():
    # remove custom SElinux modules - to be reinstalled after the upgrade
    for semodules in api.consume(SELinuxModules):
        api.current_logger().info(
            "Removing custom SELinux policy modules. Count: %d",
            len(semodules.modules))
        for module in semodules.modules:
            api.current_logger().info("Removing %s on priority %d.",
                                      module.name, module.priority)
            try:
                run([
                    'semodule', '-X',
                    str(module.priority), '-r', module.name
                ])
            except CalledProcessError as e:
                api.current_logger().warning(
                    "Failed to remove module %s on priority %d: %s",
                    module.name, module.priority, str(e.stderr))
                continue
예제 #17
0
    def process(self):
        model = next(self.consume(Authselect))
        decision = next(self.consume(AuthselectDecision))

        if not decision.confirmed or model.profile is None:
            return

        command = ['authselect', 'select', '--force', model.profile
                   ] + model.features

        try:
            run(command)
        except CalledProcessError as err:
            report_generic(title='Authselect call failed.', summary=str(err))
            return

        report_generic(title='System was converted to authselect.',
                       summary='System was converted to authselect with the '
                       'following call: "{}"'.format(' '.join(command)))
def test_split():
    """
    Test the output lines are split into lists.

    :return: Pass/Fail
    """
    cmd = ['ls']
    result = run(cmd, split=True)
    assert isinstance(result['stdout'], list)
    assert len(result['stdout']) > 1
예제 #19
0
def check_module(name):
    """
    Check if given module contains one of removed types and comment out corresponding lines.

    The function expects a text file "$name" containing cil policy
    to be present in the current directory.

    Returns a list of invalid lines.
    """
    try:
        removed = run(['grep', '-w', '-E', "|".join(REMOVED_TYPES_), name],
                      split=True)
        # Add ";" at the beginning of invalid lines (comment them out)
        run([
            'sed', '-i', '/{}/s/^/;/g'.format(r'\|'.join(REMOVED_TYPES_)), name
        ])
        return removed.get("stdout", [])
    except CalledProcessError:
        return []
def test_repos_mapping(current_actor_context):
    repos_data = [
        RepositoryData(repoid='rhel-7-server-rpms', name='RHEL 7 Server'),
        RepositoryData(repoid='rhel-7-blacklisted-rpms',
                       name='RHEL 7 Blacklisted')
    ]
    repos_files = [
        RepositoryFile(file='/etc/yum.repos.d/redhat.repo', data=repos_data)
    ]
    facts = RepositoriesFacts(repositories=repos_files)
    arch = stdlib.run(['uname', '-m'])['stdout'].strip()

    mapping = [
        RepositoryMap(from_repoid='rhel-7-server-rpms',
                      to_repoid='rhel-8-for-{}-baseos-htb-rpms'.format(arch),
                      to_pes_repo='rhel8-baseos',
                      from_minor_version='all',
                      to_minor_version='all',
                      arch=arch,
                      repo_type='rpm'),
        RepositoryMap(
            from_repoid='rhel-7-server-rpms',
            to_repoid='rhel-8-for-{}-appstream-htb-rpms'.format(arch),
            to_pes_repo='rhel8-appstream',
            from_minor_version='all',
            to_minor_version='all',
            arch=arch,
            repo_type='rpm'),
        RepositoryMap(from_repoid='rhel-7-blacklist-rpms',
                      to_repoid='rhel-8-blacklist-rpms',
                      to_pes_repo='rhel8-blacklist',
                      from_minor_version='all',
                      to_minor_version='all',
                      arch=arch,
                      repo_type='rpm')
    ]
    repos_map = RepositoriesMap(repositories=mapping)

    repos_blacklisted = RepositoriesBlacklisted(
        repoids=['rhel-8-blacklisted-rpms'])

    current_actor_context.feed(facts)
    current_actor_context.feed(repos_map)
    current_actor_context.feed(repos_blacklisted)
    current_actor_context.run()
    assert current_actor_context.consume(TargetRepositories)

    rhel_repos = current_actor_context.consume(
        TargetRepositories)[0].rhel_repos
    assert len(rhel_repos) == 2
    assert {repo.repoid
            for repo in rhel_repos} == {
                'rhel-8-for-x86_64-baseos-htb-rpms',
                'rhel-8-for-x86_64-appstream-htb-rpms'
            }
def copy_dracut_modules(modules):
    """
    Copy every dracut module with specified path into the expected directory.

    original content is overwritten if exists
    """
    # FIXME: use just python functions instead of shell cmds
    for module in modules:
        if not module.module_path:
            continue
        try:
            # context.copytree_to(module.module_path, os.path.join(DRACUT_DIR, os.path.basename(module.module_path)))
            run(['cp', '-f', '-a', module.module_path, DRACUT_DIR])
        except CalledProcessError as e:
            api.current_logger().error('Failed to copy dracut module "{name}" from "{source}" to "{target}"'.format(
                name=module.name, source=module.module_path, target=DRACUT_DIR), exc_info=True)
            # FIXME: really do we want to raise the error and stop execution completely??....
            raise StopActorExecutionError(
                message='Failed to install dracut modules required in the target initramfs. Error: {}'.format(str(e))
            )
예제 #22
0
def cleanup_scratch(scratch_dir, mounts_dir):
    """
    Function to cleanup the scratch directory
    """
    api.current_logger().debug('Cleaning up mounts')
    if os.path.ismount(mounts_dir):
        api.current_logger().debug(
            'Mounts directory is a mounted disk image - Unmounting.')
        try:
            run(['/bin/umount', '-fl', mounts_dir])
            api.current_logger().debug('Unmounted mounted disk image.')
        except (OSError, CalledProcessError) as e:
            api.current_logger().warn('Failed to umount %s - message: %s',
                                      mounts_dir, str(e))
    api.current_logger().debug('Recursively removing scratch directory %s.',
                               scratch_dir)
    shutil.rmtree(scratch_dir,
                  onerror=utils.report_and_ignore_shutil_rmtree_error)
    api.current_logger().debug('Recursively removed scratch directory %s.',
                               scratch_dir)
예제 #23
0
def guard_call(cmd, guards=(), print_output=False):
    try:
        if print_output:
            return run(cmd, callback_raw=_logging_handler), None
        return run(cmd, split=True)['stdout'], None
    except CalledProcessError as e:
        # return custom error if process failed
        error = ErrorData(details=str(e))

        # collect output from guards for possible spurious failure
        guard_errors = []
        for guard in guards:
            err = guard()
            if err:
                guard_errors.append(err)

        if guard_errors:
            error.spurious = '. Possible spurious failure: {cause}'.format(cause=' '.join(guard_errors))

        return None, error
예제 #24
0
def get_boot_partition():
    """
    Get /boot partition
    """
    try:
        # call grub2-probe to identify /boot partition
        result = run(['grub2-probe', '--target=device', '/boot'])
    except CalledProcessError:
        api.current_logger().warning(
            'Could not get name of underlying /boot partition')
        raise StopActorExecution()
    return result['stdout'].strip()
예제 #25
0
def _get_kernel_version(kernel_name):
    try:
        kernels = run(['rpm', '-q', kernel_name], split=True)['stdout']
    except CalledProcessError:
        return ''

    for kernel in kernels:
        # name-version-release - we want the last two fields only
        version = '-'.join(kernel.split('-')[-2:])
        if 'el8' in version:
            return version
    return ''
예제 #26
0
def add_boot_entry(configs=None):
    debug = 'debug' if os.getenv('LEAPP_DEBUG', '0') == '1' else ''

    kernel_dst_path, initram_dst_path = get_boot_file_paths()
    try:
        _remove_old_upgrade_boot_entry(kernel_dst_path, configs=configs)
        cmd = [
            '/usr/sbin/grubby', '--add-kernel', '{0}'.format(kernel_dst_path),
            '--initrd', '{0}'.format(initram_dst_path), '--title',
            'RHEL-Upgrade-Initramfs', '--copy-default', '--make-default',
            '--args',
            '{DEBUG} enforcing=0 rd.plymouth=0 plymouth.enable=0'.format(
                DEBUG=debug)
        ]
        if configs:
            for config in configs:
                run(cmd + ['-c', config])
        else:
            run(cmd)

        if architecture.matches_architecture(architecture.ARCH_S390X):
            # on s390x we need to call zipl explicitly because of issue in grubby,
            # otherwise the new boot entry will not be set as default
            # See https://bugzilla.redhat.com/show_bug.cgi?id=1764306
            run(['/usr/sbin/zipl'])
    except CalledProcessError as e:
        raise StopActorExecutionError(
            'Cannot configure bootloader.',
            details={'details': '{}: {}'.format(str(e), e.stderr)})
예제 #27
0
def process():
    if config.is_debug:
        try:
            # the following command prints output of grubenv for debugging purposes and is repeated after setting
            # default kernel so we can be sure we have the right saved entry
            #
            # saved_entry=63...
            # kernelopts=root=/dev/mapper...
            #
            #
            # boot_success and boot_indeterminate parameters are added later by one-shot systemd service
            stdlib.run(['grub2-editenv', 'list'])
        except stdlib.CalledProcessError:
            api.current_logger().error(
                'Failed to execute "grub2-editenv list" command')
    message = next(api.consume(InstalledTargetKernelVersion), None)
    if not message:
        api.current_logger().warning((
            'Skipped - Forcing checking and setting default boot entry to target kernel'
            ' version due to missing message'))
        return

    try:
        current_default_kernel = stdlib.run(['grubby', '--default-kernel'
                                             ])['stdout'].strip()
    except (OSError, stdlib.CalledProcessError):
        api.current_logger().warning(
            'Failed to query grubby for default kernel', exc_info=True)
        return

    for type_ in ('index', 'title'):
        try:
            stdlib.run(['grubby', '--default-{}'.format(type_)])
        except (OSError, stdlib.CalledProcessError):
            api.current_logger().warning(
                'Failed to query grubby for default {}'.format(type_),
                exc_info=True)
            return

    kernel_info = get_kernel_info(message)
    if not kernel_info:
        return

    if current_default_kernel != kernel_info.kernel_path:
        api.current_logger().warning((
            'Current default boot entry not target kernel version: Current default: %s.'
            'Forcing default kernel to %s'), current_default_kernel,
                                     kernel_info.kernel_path)
        update_default_kernel(kernel_info)
    if config.is_debug:
        try:
            stdlib.run(['grub2-editenv', 'list'])
        except stdlib.CalledProcessError:
            api.current_logger().error(
                'Failed to execute "grub2-editenv list" command')
예제 #28
0
def remove_boot_entry():
    # we need to make sure /boot is mounted before trying to remove the boot entry

    facts_msg = api.consume(FirmwareFacts)
    facts = next(facts_msg, None)
    if not facts:
        raise StopActorExecutionError('Could not identify system firmware',
                                      details={'details': 'Actor did not receive FirmwareFacts message.'})

    mount_points_per_firmware = {
        'bios': ['/boot'],
        'efi': ['/boot', '/boot/efi']
    }

    for mp in mount_points_per_firmware[facts.firmware]:
        try:
            run(['/bin/mount', mp])
        except CalledProcessError:
            # partitions have been most likely already mounted
            pass
    kernel_filepath = get_upgrade_kernel_filepath()
    run([
        '/usr/sbin/grubby',
        '--remove-kernel={0}'.format(kernel_filepath)
    ])
    # TODO: Move calling `mount -a` to a separate actor as it is not really related to removing the upgrade boot entry.
    #       It's worth to call it after removing the boot entry to avoid boot loop in case mounting fails.
    run([
        '/bin/mount', '-a'
    ])
예제 #29
0
    def process(self):
        model = next(self.consume(Authselect))
        decision = next(self.consume(AuthselectDecision))

        if not decision.confirmed or model.profile is None:
            return

        command = ['authselect', 'select', '--force', model.profile
                   ] + model.features

        try:
            run(command)
        except CalledProcessError as err:
            create_report([  # pylint: disable-msg=too-many-arguments
                reporting.Title('Authselect call failed'),
                reporting.Summary(str(err)),
                reporting.Severity(reporting.Severity.MEDIUM),
                reporting.Tags([
                    reporting.Tags.AUTHENTICATION, reporting.Tags.SECURITY,
                    reporting.Tags.TOOLS
                ]),
                reporting.Flags([reporting.Flags.FAILURE])
            ] + resources)  # pylint: disable-msg=too-many-arguments
            return

        try:
            run(['systemctl', 'enable', 'oddjobd.service'])
        except (OSError, CalledProcessError) as e:
            self.log.warning('Error enabling oddjobd.service: {}'.format(e))

        create_report([  # pylint: disable-msg=too-many-arguments
            reporting.Title('System was converted to authselect.'),
            reporting.Summary('System was converted to authselect with the '
                              'following call: "{}"'.format(
                                  ' '.join(command))),
            reporting.Tags([
                reporting.Tags.AUTHENTICATION, reporting.Tags.SECURITY,
                reporting.Tags.TOOLS
            ])
        ] + resources)  # pylint: disable-msg=too-many-arguments
예제 #30
0
def get_installed_rpms():
    rpm_cmd = [
        '/bin/rpm', '-qa', '--queryformat',
        r'%{NAME}|%{VERSION}|%{RELEASE}|%|EPOCH?{%{EPOCH}}:{(none)}||%|PACKAGER?{%{PACKAGER}}:{(none)}||%|'
        r'ARCH?{%{ARCH}}:{}||%|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{(none)}|}|\n'
    ]
    try:
        return stdlib.run(rpm_cmd, split=True)['stdout']
    except stdlib.CalledProcessError as err:
        error = 'Execution of {CMD} returned {RC}. Unable to find installed packages.'.format(
            CMD=err.command, RC=err.exit_code)
        stdlib.api.current_logger().error(error)
        return []