Exemple #1
0
def mount_system(root_path, fstab):
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Mount system in {0}'.format(root_path))
    system_mount = Fstab()
    try:
        for fstab_entry in fstab.get_devices():
            mountpoint = ''.join([root_path, fstab_entry.mountpoint])
            log.info('Mounting {0}'.format(mountpoint))
            Command.run([
                'mount', '-o', fstab_entry.options, fstab_entry.device,
                mountpoint
            ])
            system_mount.add_entry(fstab_entry.device, mountpoint,
                                   fstab_entry.fstype)

        log.info('Mounting kernel file systems inside {0}'.format(root_path))
        dev_mount_point = os.sep.join([root_path, 'dev'])
        Command.run(['mount', '-t', 'devtmpfs', 'devtmpfs', dev_mount_point])
        system_mount.add_entry('devtmpfs', dev_mount_point)
        proc_mount_point = os.sep.join([root_path, 'proc'])
        Command.run(['mount', '-t', 'proc', 'proc', proc_mount_point])
        system_mount.add_entry('/proc', proc_mount_point)
        sys_mount_point = os.sep.join([root_path, 'sys'])
        Command.run(['mount', '-t', 'sysfs', 'sysfs', sys_mount_point])
        system_mount.add_entry('sysfs', sys_mount_point)
    except Exception as issue:
        log.error('Mounting system for upgrade failed with {0}'.format(issue))
        raise DistMigrationSystemMountException(
            'Mounting system for upgrade failed with {0}'.format(issue))
    system_mount.export(Defaults.get_system_mount_info_file())
Exemple #2
0
def main():
    """
    DistMigration post mount actions

    Preserve custom data file(s) e.g udev rules from the system
    to be migrated to the live migration system and activate
    those file changes to become effective
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    root_path = Defaults.get_system_root_path()

    migration_config = MigrationConfig()
    system_udev_rules = migration_config.get_preserve_udev_rules_list()
    if system_udev_rules:
        for rule_file in system_udev_rules:
            target_rule_dir = os.path.dirname(rule_file)
            source_rule_file = os.path.normpath(
                os.sep.join([root_path, rule_file]))
            log.info('Copy udev rule: {0} to: {1}'.format(
                source_rule_file, target_rule_dir))
            shutil.copy(source_rule_file, target_rule_dir)
        Command.run(['udevadm', 'control', '--reload'])
        Command.run(
            ['udevadm', 'trigger', '--type=subsystems', '--action=add'])
        Command.run(['udevadm', 'trigger', '--type=devices', '--action=add'])
Exemple #3
0
def main():
    """
    DistMigration update grub to migrated version

    Setup and update grub with content from the migrated system
    Uninstall live migration packages such that they are no longer
    part of the now migrated system.
    """
    root_path = Defaults.get_system_root_path()
    grub_config_file = Defaults.get_grub_config_file()

    try:
        log.info('Running grub setup service')
        migration_packages = ['SLE*-Migration', 'suse-migration-*-activation']
        log.info('Uninstalling migration: {0}{1}'.format(
            os.linesep,
            Command.run([
                'chroot', root_path, 'zypper', '--non-interactive',
                '--no-gpg-checks', 'remove'
            ] + migration_packages,
                        raise_on_error=False).output))
        log.info('Creating new grub menu: {0}{1}'.format(
            os.linesep,
            Command.run([
                'chroot', root_path, 'grub2-mkconfig', '-o',
                '{0}{1}'.format(os.sep, grub_config_file)
            ]).error))
    except Exception as issue:
        message = 'Update grub failed with {0}'.format(issue)
        log.error(message)
        raise DistMigrationGrubConfigException(message)
def mount_system(root_path, fstab):
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Mount system in {0}'.format(root_path))
    system_mount = Fstab()
    explicit_mount_points = {
        'devtmpfs': os.sep.join([root_path, 'dev']),
        'proc': os.sep.join([root_path, 'proc']),
        'sysfs': os.sep.join([root_path, 'sys'])
    }
    try:
        for fstab_entry in fstab.get_devices():
            mountpoint = ''.join([root_path, fstab_entry.mountpoint])
            if mountpoint not in explicit_mount_points.values():
                if fstab_entry.eligible_for_mount:
                    log.info('Mounting {0}'.format(mountpoint))
                    Command.run([
                        'mount', '-o', fstab_entry.options, fstab_entry.device,
                        mountpoint
                    ])
                system_mount.add_entry(fstab_entry.device, mountpoint,
                                       fstab_entry.fstype,
                                       fstab_entry.eligible_for_mount)

        log.info('Mounting kernel file systems inside {0}'.format(root_path))
        for mount_type, mount_point in explicit_mount_points.items():
            Command.run(['mount', '-t', mount_type, mount_type, mount_point])
            system_mount.add_entry(mount_type, mount_point)
    except Exception as issue:
        log.error('Mounting system for upgrade failed with {0}'.format(issue))
        raise DistMigrationSystemMountException(
            'Mounting system for upgrade failed with {0}'.format(issue))
    system_mount.export(Defaults.get_system_mount_info_file())
Exemple #5
0
def main():
    """
    DistMigration load new kernel for kexec reboot

    Loads the new kernel/initrd after migration for system reboot
    """
    root_path = Defaults.get_system_root_path()

    target_kernel = os.sep.join([root_path, Defaults.get_target_kernel()])
    target_initrd = os.sep.join([root_path, Defaults.get_target_initrd()])
    kexec_boot_data = '/var/tmp/kexec'
    Path.create(kexec_boot_data)
    shutil.copy(target_initrd, kexec_boot_data)
    try:
        log.info('Running kernel load service')
        log.info('Loading the target kernel')
        Command.run([
            'kexec', '--load', target_kernel, '--initrd',
            os.sep.join([kexec_boot_data,
                         os.path.basename(target_initrd)]), '--command-line',
            _get_cmdline(os.path.basename(target_kernel))
        ])
    except Exception as issue:
        log.error('Kernel load service raised exception: {0}', format(issue))
        raise DistMigrationKernelRebootException(
            'Failed to load kernel/initrd into memory: {0}'.format(issue))
Exemple #6
0
def main():
    """
    DistMigration load new kernel for kexec reboot

    Loads the new kernel/initrd after migration for system reboot
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    if not MigrationConfig().is_soft_reboot_requested():
        log.info('skipping kexec --load (hard reboot requested)')
        return

    root_path = Defaults.get_system_root_path()

    target_kernel = os.sep.join([root_path, Defaults.get_target_kernel()])
    target_initrd = os.sep.join([root_path, Defaults.get_target_initrd()])
    kexec_boot_data = '/var/tmp/kexec'
    Path.create(kexec_boot_data)
    shutil.copy(target_initrd, kexec_boot_data)
    try:
        log.info('Running kernel load service')
        log.info('Loading the target kernel')
        Command.run([
            'kexec', '--load', target_kernel, '--initrd',
            os.sep.join([kexec_boot_data,
                         os.path.basename(target_initrd)]),
            '--kexec-file-syscall', '--command-line',
            _get_cmdline(os.path.basename(target_kernel))
        ])
    except Exception as issue:
        log.error('Kernel load service raised exception: {0}'.format(issue))
        raise DistMigrationKernelRebootException(
            'Failed to load kernel/initrd into memory: {0}'.format(issue))
def main():
    """
    DistMigration post mount actions

    Preserve custom data file(s) e.g udev rules from the system
    to be migrated to the live migration system and activate
    those file changes to become effective
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    root_path = Defaults.get_system_root_path()

    migration_config = MigrationConfig()
    preserve_info = migration_config.get_preserve_info()
    if preserve_info:
        for _, preserve_files in preserve_info.items():
            for preserve_file in preserve_files:
                target_dir = os.path.dirname(preserve_file)
                source_file = os.path.normpath(
                    os.sep.join([root_path, preserve_file]))
                log.info('Copy file: {0} to: {1}'.format(
                    source_file, target_dir))
                if not os.path.exists(target_dir):
                    Command.run(['mkdir', '-p', target_dir])
                shutil.copy(source_file, target_dir)
        if 'rules' in preserve_info.keys():
            Command.run(['udevadm', 'control', '--reload'])
            Command.run(
                ['udevadm', 'trigger', '--type=subsystems', '--action=add'])
            Command.run(
                ['udevadm', 'trigger', '--type=devices', '--action=add'])
 def __init__(self):
     self.config_data = {}
     self.migration_config_file = \
         Defaults.get_migration_config_file()
     self.migration_custom_file = \
         Defaults.get_system_migration_custom_config_file()
     with open(self.migration_config_file, 'r') as config:
         self.config_data = yaml.safe_load(config)
def main():
    """
    DistMigration ssh access for migration user

    Copy the authoritation key found to the migration user
    directory in order to access through ssh
    """
    ssh_keys_glob_paths = Defaults.get_ssh_keys_paths()
    migration_ssh_file = Defaults.get_migration_ssh_file()
    system_ssh_host_keys_glob_path = \
        Defaults.get_system_ssh_host_keys_glob_path()
    sshd_config_path = Defaults.get_system_sshd_config_path()
    try:
        log.info('Running ssh keys service')
        ssh_keys_paths = []
        for glob_path in ssh_keys_glob_paths:
            ssh_keys_paths.extend(glob.glob(glob_path))

        keys_list = []
        for ssh_keys_path in ssh_keys_paths:
            log.info('Getting keys from {0}'.format(ssh_keys_path))
            with open(ssh_keys_path) as authorized_keys_file:
                keys_list.append(authorized_keys_file.read())

        authorized_keys_content = ''.join(keys_list)
        log.info('Save keys to {0}'.format(migration_ssh_file))
        with open(migration_ssh_file, 'w') as authorized_migration_file:
            authorized_migration_file.write(authorized_keys_content)

        system_ssh_host_keys = glob.glob(system_ssh_host_keys_glob_path)
        sshd_config_host_keys_entries = []
        log.info('Copying host ssh keys')
        for system_ssh_host_key in system_ssh_host_keys:
            if not system_ssh_host_key.endswith('ssh_host_key'):
                shutil.copy(system_ssh_host_key, '/etc/ssh/')

                if not system_ssh_host_key.endswith('.pub'):
                    live_private_ssh_host_key_path = os.sep.join([
                        os.path.dirname(sshd_config_path),
                        os.path.basename(system_ssh_host_key)
                    ])
                    entry = 'HostKey {0}'.format(
                        live_private_ssh_host_key_path)
                    sshd_config_host_keys_entries.append(entry)

        with open(sshd_config_path, 'a') as live_sshd_config_file:
            # write one newline to be sure any subsequent
            # HostKey entry starts correctly
            live_sshd_config_file.write(os.linesep)
            live_sshd_config_file.write(
                os.linesep.join(sshd_config_host_keys_entries))
        log.info('Restarting sshd')
        Command.run(['systemctl', 'restart', 'sshd'])
    except Exception as issue:
        log.error('SSH key/identity setup failed with: {0}. {1}'.format(
            issue, 'Continue without ssh access'))
Exemple #10
0
def main():
    """
    DistMigration reboot with new kernel

    After the migration process is finished, the system reboots
    unless the debug option is set.

    Before reboot a reverse umount of the filesystems that got mounted
    by the mount_system service is performed and thus releases the
    upgraded system from the migration host. If for whatever reason
    a filesystem is busy and can't be umounted, this condition is not
    handled as an error. The reason is that the cleanup should not
    prevent us from continuing with the reboot process. The risk on
    reboot of the migration host with a potential active mount
    is something we accept
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    try:
        log.info('Systemctl Status Information: {0}{1}'.format(
            os.linesep,
            Command.run(['systemctl', 'status', '-l', '--all'],
                        raise_on_error=False).output))
        # stop console dialog log. The service holds a busy state
        # on system-root and stands in our way in case of debug
        # mode because it grabs the master console in/output
        Command.run(['systemctl', 'stop', 'suse-migration-console-log'],
                    raise_on_error=False)
        if MigrationConfig().is_debug_requested():
            log.info('Reboot skipped due to debug flag set')
        else:
            log.info('Umounting system')
            system_mount = Fstab()
            system_mount.read(Defaults.get_system_mount_info_file())
            for mount in reversed(system_mount.get_devices()):
                log.info('Umounting {0}: {1}'.format(
                    mount.mountpoint,
                    Command.run(['umount', '--lazy', mount.mountpoint],
                                raise_on_error=False)))
            if not MigrationConfig().is_soft_reboot_requested():
                restart_system = 'reboot'
            else:
                restart_system = 'kexec'
            log.info('Reboot system: {0}{1}'.format(
                os.linesep, Command.run(['systemctl', restart_system])))
    except Exception:
        # Uhh, we don't want to be here, but we also don't
        # want to be stuck in the migration live system.
        # Keep fingers crossed:
        log.warning('Reboot system: [Force Reboot]')
        Command.run(['systemctl', '--force', 'reboot'])
def main():
    """
    DistMigration mount system to upgrade

    Searches on all partitions for a fstab file. The first
    fstab file found is used as the system to upgrade.
    Filesystems relevant for an upgrade process are read from
    that fstab in order and mounted such that the system rootfs
    is available for a zypper based migration process.
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    root_path = Defaults.get_system_root_path()
    Path.create(root_path)
    log.info('Running mount system service')

    if is_mounted(root_path):
        # root_path is already a mount point, better not continue
        # The condition is not handled as an error because the
        # existing mount point under this service created root_path
        # is considered to represent the system to upgrade and
        # not something else. Thus if already mounted, let's use
        # what is there.
        return

    log.info('Mount system service: {0} is mounted'.format(root_path))
    # Check if booted via loopback grub
    isoscan_loop_mount = '/run/initramfs/isoscan'
    if is_mounted(isoscan_loop_mount):
        # The system to become migrated was booted via a grub
        # loopback menuentry. This means the disk is blocked by
        # that readonly loopback mount and needs to be
        # remounted for read write access first
        log.info(
            'Mount system service: {0} is mounted'.format(isoscan_loop_mount))
        Command.run(['mount', '-o', 'remount,rw', isoscan_loop_mount])

    fstab, storage_info = read_system_fstab(root_path)
    if not fstab:
        log.error('Could not find system in fstab on {0}'.format(storage_info))
        raise DistMigrationSystemNotFoundException(
            'Could not find system with fstab on {0}'.format(storage_info))

    mount_system(root_path, fstab)

    migration_config = MigrationConfig()
    migration_config.update_migration_config_file()
    log.info('Config file content:\n{content}\n'.format(
        content=migration_config.get_migration_config_file_content()))
Exemple #12
0
def main():
    """
    DistMigration run zypper based migration

    Call zypper migration plugin and migrate the system.
    The output of the call is logged on the system to migrate
    """
    root_path = Defaults.get_system_root_path()

    try:
        log.info('Running migrate service')
        migration_config = MigrationConfig()
        if migration_config.is_zypper_migration_plugin_requested():
            bash_command = ' '.join([
                'zypper', 'migration', '--non-interactive',
                '--gpg-auto-import-keys', '--no-selfupdate',
                '--auto-agree-with-licenses', '--allow-vendor-change',
                '--strict-errors-dist-migration', '--replacefiles',
                '--product',
                migration_config.get_migration_product(), '--root', root_path,
                '&>>',
                Defaults.get_migration_log_file()
            ])
            Command.run(['bash', '-c', bash_command])
        else:
            bash_command = ' '.join([
                'zypper', '--non-interactive', '--gpg-auto-import-keys',
                '--root', root_path, 'dup', '--auto-agree-with-licenses',
                '--allow-vendor-change', '--replacefiles', '&>>',
                Defaults.get_migration_log_file()
            ])
            zypper_call = Command.run(['bash', '-c', bash_command],
                                      raise_on_error=False)
            if zypper_has_failed(zypper_call.returncode):
                raise DistMigrationCommandException(
                    '{0} failed with: {1}: {2}'.format(bash_command,
                                                       zypper_call.output,
                                                       zypper_call.error))
    except Exception as issue:
        etc_issue_path = os.sep.join([root_path, 'etc/issue'])
        log_path_migrated_system = os.sep + os.path.relpath(
            Defaults.get_migration_log_file(), root_path)
        with open(etc_issue_path, 'w') as issue_file:
            issue_file.write(
                'Migration has failed, for further details see {0}'.format(
                    log_path_migrated_system))
        log.error('migrate service failed with {0}'.format(issue))
        raise DistMigrationZypperException(
            'Migration failed with {0}'.format(issue))
def main():
    """
    DistMigration create a new initrd with added modules

    Run dracut to build a new initrd that includes multipath modules
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())

    if MigrationConfig().is_host_independent_initd_requested():
        log.info('Creating a new host independent initrd')
        root_path = Defaults.get_system_root_path()

        dracut_bind_mounts(root_path)
        run_dracut(root_path)
Exemple #14
0
    def setup():
        logger = logging.getLogger(Defaults.get_migration_log_name())
        logger.setLevel(logging.INFO)

        log_file = Defaults.get_migration_log_file()
        Path.create(os.path.dirname(log_file))

        log_to_file = logging.FileHandler(log_file)
        log_to_file.setLevel(logging.INFO)

        log_to_stream = logging.StreamHandler()
        log_to_stream.setLevel(logging.INFO)

        logger.addHandler(log_to_stream)
        logger.addHandler(log_to_file)
def main():
    """
    DistMigration activate host network setup

    Setup and activate the network as it is setup on the host
    to become migrated. This includes the import of the resolver
    and network configuration from the migration host
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    root_path = Defaults.get_system_root_path()

    resolv_conf = os.sep.join([root_path, 'etc', 'resolv.conf'])
    if not os.path.exists(resolv_conf):
        raise DistMigrationNameResolverException(
            'Could not find {0} on migration host'.format(resolv_conf))
    if has_host_resolv_setup(resolv_conf):
        log.info('Copying {}'.format(resolv_conf))
        shutil.copy(resolv_conf, '/etc/resolv.conf')
    else:
        log.info('Empty {}, continuing without copying it'.format(resolv_conf))

    sysconfig_network_providers = os.sep.join(
        [root_path, 'etc', 'sysconfig', 'network', 'providers'])
    sysconfig_network_setup = os.sep.join(
        [root_path, 'etc', 'sysconfig', 'network', '*'])
    try:
        log.info('Running setup host network service')
        system_mount = Fstab()
        system_mount.read(Defaults.get_system_mount_info_file())
        Command.run([
            'mount', '--bind', sysconfig_network_providers,
            '/etc/sysconfig/network/providers'
        ])
        system_mount.add_entry(sysconfig_network_providers,
                               '/etc/sysconfig/network/providers')
        for network_setup in glob.glob(sysconfig_network_setup):
            if os.path.isfile(network_setup):
                shutil.copy(network_setup, '/etc/sysconfig/network')
        Command.run(['systemctl', 'reload', 'network'])
        system_mount.export(Defaults.get_system_mount_info_file())
    except Exception as issue:
        log.error(
            'Preparation of migration host network failed with {0}'.format(
                issue))
        raise DistMigrationHostNetworkException(
            'Preparation of migration host network failed with {0}'.format(
                issue))
    def test_mount_system_raises(self, mock_Command_run, mock_logger_setup,
                                 mock_os_path_exists):
        def skip_device(device):
            if '/dev/mynode' in device:
                return False
            return True

        def command_calls(command):
            # mock error on mounting home
            if '/system-root/home' in command:
                raise Exception

        mock_os_path_exists.side_effect = skip_device
        mock_Command_run.side_effect = command_calls
        with raises(DistMigrationSystemMountException):
            fstab = Fstab()
            fstab.read('../data/fstab')
            mount_system(Defaults.get_system_root_path(), fstab)
        assert mock_Command_run.call_args_list == [
            call([
                'mount', '-o', 'acl,user_xattr',
                '/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2',
                '/system-root/'
            ]),
            call([
                'mount', '-o', 'defaults', '/dev/disk/by-partuuid/3c8bd108-01',
                '/system-root/bar'
            ]),
            call([
                'mount', '-o', 'defaults', '/dev/disk/by-label/foo',
                '/system-root/home'
            ])
        ]
Exemple #17
0
def remote_repos():
    log = logging.getLogger(Defaults.get_migration_log_name())
    repos_path = '/etc/zypp/repos.d'
    no_remote_repos = []

    if os.path.exists(repos_path):
        repos_list = os.listdir(repos_path)
        config = configparser.RawConfigParser()
        if not repos_list:
            log.error('No repositories in {}'.format(repos_path))
            return

        migration_accepted_prefixes = ('http', 'ftp', 'plugin:/susecloud')
        for repo in repos_list:
            repo_path = os.sep.join([repos_path, repo])
            config.read(repo_path)
            repo_section = dict(config)
            for section in repo_section.keys():
                repo_info = dict(config.items(section))
                if repo_info:
                    if not repo_info['baseurl'].startswith(
                            migration_accepted_prefixes):
                        if repo_info['baseurl'] not in no_remote_repos:
                            no_remote_repos.append(repo_info['baseurl'])

    if no_remote_repos:
        zypper_cmd = 'zypper repos --url'
        log.warning(
            'The following repositories may cause the migration to fail, as they '
            'may not be available during the migration:\n%s\nPlease, check those '
            'before starting the migration\nTo see all the repositories and '
            'their urls, you can run "%s"\n',
            '\n'.join(no_remote_repos),
            zypper_cmd,
        )
 def test_get_cmd_line_grub_cfg_not_present(
     self, mock_os_path_exists, mock_logger_setup
 ):
     mock_os_path_exists.return_value = False
     with self._caplog.at_level(logging.ERROR):
         with raises(DistMigrationKernelRebootException):
             _get_cmdline(Defaults.get_grub_config_file())
def main():
    """
    DistMigration setup baseproduct for migration

    Creates a backup of the system products data and prepares
    the baseproduct to be suitable for the distribution migration.
    In case of an error the backup information is used by the
    zypper migration plugin to restore the original product
    data such that the plugin's rollback mechanism is not
    negatively influenced.
    """
    Logger.setup()
    log = logging.getLogger(Defaults.get_migration_log_name())
    try:
        # Note:
        # zypper implements a handling for the distro_target attribute.
        # If present in the repository metadata, zypper compares the
        # value with the baseproduct <target> setup in /etc/products.d.
        # If they mismatch zypper refuses to create the repo. In the
        # process of a migration from distribution [A] to [B] this mismatch
        # always applies by design and prevents the zypper migration
        # plugin to work. In SCC or RMT the repositories doesn't
        # contain the distro_target attribute which is the reason
        # why we don't see this problem there. SMT however creates repos
        # including distro_target. The current workaround solution is
        # to delete the target specification in the baseproduct
        # registration if present.
        log.info('Updating Base Product to be suitable for migration')
        SUSEBaseProduct().delete_target_registration()
    except Exception as issue:
        message = 'Base Product update failed with: {0}'.format(issue)
        log.error(message)
        raise DistMigrationProductSetupException(message)
    def __init__(self):
        root_path = Defaults.get_system_root_path()
        self.products_metadata = os.sep.join([root_path, 'etc', 'products.d'])
        self.prod_filenames = glob.glob(
            os.path.join(self.products_metadata, '*.prod'))
        base_product_files = []
        xml = ElementTree()
        for prod_filename in self.prod_filenames:
            try:
                xml.parse(prod_filename)
                register_sections = xml.findall('register')
                for register in register_sections:
                    flavor = register.findall('flavor')
                    if not flavor:
                        base_product_files.append(prod_filename)

            except Exception as issue:
                message = \
                    'Parsing XML file {0} failed with: {1}'.format(
                        prod_filename, issue
                    )
                log.warning(message)

        if len(base_product_files) != 1:
            if not base_product_files:
                message = 'There is no baseproduct'
            else:
                message = ('Found multiple product definitions '
                           'without element <flavor>: \n{0}'.format(
                               '\n'.join(base_product_files)))
            log.error(message)
            raise DistMigrationSUSEBaseProductException(message)

        self.base_product = base_product_files[0]
def dracut_bind_mounts(root_path,):
    """Function to do bind mounts needed before running dracut"""

    log = logging.getLogger(Defaults.get_migration_log_name())

    BIND_DIRS = ['/dev', '/proc', '/sys']

    for bind_dir in BIND_DIRS:
        try:
            log.info(
                'Running mount --bind {0} {1}'.format(bind_dir, root_path + bind_dir)
            )
            Command.run(
                [
                    'mount',
                    '--bind',
                    bind_dir,
                    root_path + bind_dir
                ]
            )
        except Exception as issue:
            log.error(
                'Unable to mount: {0}'.format(issue)
            )
            raise DistMigrationCommandException(
                'Unable to mount: {0}'.format(
                    issue
                )
            ) from issue
Exemple #22
0
def read_system_fstab(root_path):
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Reading fstab from associated disks')
    lsblk_call = Command.run(['lsblk', '-p', '-n', '-r', '-o', 'NAME,TYPE'])
    considered_block_types = ['part', 'raid', 'lvm']
    considered_block_devices = []
    lvm_managed_block_device_found = False
    for entry in lsblk_call.output.split(os.linesep):
        block_record = entry.split()
        if len(block_record) >= 2:
            block_type = block_record[1]
            if block_type in considered_block_types:
                if block_type == 'lvm':
                    lvm_managed_block_device_found = True
                considered_block_devices.append(block_record[0])

    if lvm_managed_block_device_found:
        log.info('LVM managed block device(s) found, activating volume groups')
        Command.run(['vgchange', '-a', 'y'])

    for block_device in considered_block_devices:
        try:
            Command.run(['mount', block_device, root_path],
                        raise_on_error=False)
            fstab_file = os.sep.join([root_path, 'etc', 'fstab'])
            if os.path.exists(fstab_file):
                fstab = Fstab()
                fstab.read(fstab_file)
                return (fstab, lsblk_call.output)
        finally:
            log.info('Umount {0}'.format(root_path))
            Command.run(['umount', root_path], raise_on_error=False)
    return (None, lsblk_call.output)
Exemple #23
0
class TestDefaults(object):
    def setup(self):
        self.defaults = Defaults()

    def test_get_migration_config_file(self):
        assert self.defaults.get_migration_config_file() == \
            '/etc/migration-config.yml'

    def test_get_os_release(self):
        os_release_tuple = namedtuple('OSRelease', [
            'name', 'version', 'version_id', 'pretty_name', 'id', 'id_like',
            'ansi_color', 'cpe_name'
        ])
        os_release_result = os_release_tuple(
            name='SLES',
            version='15-SP1',
            version_id='15.1',
            pretty_name='SUSE Linux Enterprise Server 15 SP1',
            id='sles',
            id_like='suse',
            ansi_color='0;32',
            cpe_name='cpe:/o:suse:sles:15:sp1')
        os_release_content = (
            'NAME="SLES"\n'
            'VERSION="15-SP1"\n'
            'VERSION_ID="15.1"\n'
            'PRETTY_NAME="SUSE Linux Enterprise Server 15 SP1"\n'
            'ID="sles"\n'
            'ID_LIKE="suse"\n'
            'ANSI_COLOR="0;32"\n'
            'CPE_NAME="cpe:/o:suse:sles:15:sp1"')
        with patch('builtins.open', create=True) as mock_open:
            mock_open_os_release = MagicMock(spec=io.IOBase)

            def open_file(filename, mode):
                if filename == '/etc/os-release':
                    return mock_open_os_release.return_value

            mock_open.side_effect = open_file
            file_handle = \
                mock_open_os_release.return_value.__enter__.return_value
            file_handle.read.return_value = os_release_content
            assert self.defaults.get_os_release() == os_release_result

    def test_get_proxy_path(self):
        assert self.defaults.get_proxy_path() == \
            '/etc/sysconfig/proxy'
def is_mounted(mount_point):
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Checking {0} is mounted'.format(mount_point))
    # a bind mount is neither a device nor an inode.
    # Thus, ismount will return False for those, as
    # it is very unlikely that a bind mount is used in fstab,
    # that case is not handled
    return os.path.ismount(mount_point)
Exemple #25
0
 def test_get_cmd_line_grub_cfg_not_present(
     self, mock_os_path_exists, mock_info, mock_error
 ):
     mock_os_path_exists.return_value = False
     with raises(DistMigrationKernelRebootException):
         _get_cmdline(Defaults.get_grub_config_file())
         assert mock_info.called
         assert mock_error.called
Exemple #26
0
def log_init():
    logging.setLoggerClass(Logger)
    log = logging.getLogger("suse-migration")
    log.setLevel(logging.DEBUG)

    log_file = Defaults.get_migration_log_file()
    if os.path.exists(log_file):
        log.set_logfile(log_file)
    return log
Exemple #27
0
def is_mounted(mount_point):
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Checking {0} is mounted'.format(mount_point))
    if os.path.exists(mount_point):
        mountpoint_call = Command.run(['mountpoint', '-q', mount_point],
                                      raise_on_error=False)
        if mountpoint_call.returncode == 0:
            return True
    return False
Exemple #28
0
 def test_main_system_already_mounted(self, mock_path_ismount,
                                      mock_path_create, mock_logger_setup):
     mock_path_ismount.return_value = True
     logger = logging.getLogger(Defaults.get_migration_log_name())
     with patch.object(logger, 'info') as mock_info:
         main()
         mock_path_create.assert_called_once_with('/system-root')
         assert mock_info.call_args_list == [
             call('Running mount system service'),
             call('Checking /system-root is mounted')
         ]
Exemple #29
0
def main():
    """
    DistMigration pre checks before migration starts

    Checks whether
      - repositories' locations are not remote
      - filesystems in fstab are using LUKS encryption
    """
    Logger.setup(system_root=False)
    log = logging.getLogger(Defaults.get_migration_log_name())
    log.info('Running pre migration checks')
    check_repos.remote_repos()
    check_fs.encryption()
Exemple #30
0
def _get_cmdline(kernel_name):
    log.info('Getting cmdline for {0}'.format(kernel_name))
    grub_config_file_path = os.sep.join(
        [Defaults.get_system_root_path(),
         Defaults.get_grub_config_file()])
    if not os.path.exists(grub_config_file_path):
        log.error('kernel load service was not able to find'
                  '{0}'.format(grub_config_file_path))
        raise DistMigrationKernelRebootException(
            'Could not find {0} to load the kernel options'.format(
                grub_config_file_path))
    with open(grub_config_file_path) as grub_config_file:
        grub_content = grub_config_file.read()
    pattern = r'(?<=linux)[ \t]+{0}([{1}|boot/{1}].*)'.format(
        os.sep, kernel_name)
    cmd_line = re.findall(pattern, grub_content)[0]
    cmd_line = cmd_line.split()
    cmd_line_options = []
    for option in cmd_line:
        if kernel_name not in option:
            cmd_line_options.append(option)
    return ' '.join(cmd_line_options)