def test_read_with_skipped_entries(self, mock_os_path_exists, mock_log_warning): mock_os_path_exists.return_value = False fstab = Fstab() fstab.read('../data/fstab') mock_log_warning.assert_called_once_with( 'Device path /dev/mynode not found and skipped') assert fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults') ]
def test_read_with_skipped_entries(self, mock_os_path_exists): def skip_device(device): if '/dev/mynode' in device: return False return True mock_os_path_exists.side_effect = skip_device fstab = Fstab() with self._caplog.at_level(logging.WARNING): fstab.read('../data/fstab') assert 'Device path /dev/mynode not found and skipped' in \ self._caplog.text assert fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults') ]
def test_main_kexec_reboot(self, mock_Fstab, mock_Command_run, mock_logger_setup, mock_get_migration_config_file, mock_os_path_exists): def skip_device(device): if '/dev/mynode' in device: return False return True mock_os_path_exists.side_effect = skip_device fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/system-root.fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_Fstab.return_value = fstab_mock mock_get_migration_config_file.return_value = \ '../data/migration-config.yml' main() assert mock_Command_run.call_args_list == [ call(['systemctl', 'status', '-l', '--all'], raise_on_error=False), call(['systemctl', 'stop', 'suse-migration-console-log'], raise_on_error=False), call(['umount', '--lazy', '/system-root/home'], raise_on_error=False), call(['umount', '--lazy', '/system-root/boot/efi'], raise_on_error=False), call(['umount', '--lazy', '/system-root/'], raise_on_error=False), call(['systemctl', 'kexec']) ]
def test_main_force_reboot(self, mock_Fstab, mock_Command_run, mock_info, mock_warning, mock_get_migration_config_file): fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/system-root.fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_Fstab.return_value = fstab_mock mock_Command_run.side_effect = [ MagicMock(), MagicMock(), MagicMock(), MagicMock(), Exception, None ] mock_get_migration_config_file.return_value = \ '../data/migration-config.yml' main() assert mock_info.called assert mock_Command_run.call_args_list == [ call(['systemctl', 'status', '-l', '--all'], raise_on_error=False), call(['umount', '--lazy', '/system-root/home'], raise_on_error=False), call(['umount', '--lazy', '/system-root/boot/efi'], raise_on_error=False), call(['umount', '--lazy', '/system-root/'], raise_on_error=False), call(['systemctl', 'reboot']), call(['systemctl', '--force', 'reboot']) ] mock_warning.assert_called_once_with('Reboot system: [Force Reboot]')
def test_add_entry(self): fstab = Fstab() fstab.add_entry('/dev/sda', '/foo') assert fstab.get_devices() == [ fstab.fstab_entry_type(fstype='none', mountpoint='/foo', device='/dev/sda', options='defaults') ]
def test_main_force_reboot( self, mock_Fstab, mock_get_migration_config_file, mock_logger_setup, mock_Command_run, mock_os_path_exists ): def skip_device(device): if '/dev/mynode' in device: return False return True mock_os_path_exists.side_effect = skip_device fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/system-root.fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_Fstab.return_value = fstab_mock mock_Command_run.side_effect = [ MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock(), Exception, None ] mock_get_migration_config_file.return_value = \ '../data/migration-config-hard-reboot.yml' with self._caplog.at_level(logging.WARNING): main() assert mock_Command_run.call_args_list == [ call( ['systemctl', 'status', '-l', '--all'], raise_on_error=False ), call( ['systemctl', 'stop', 'suse-migration-console-log'], raise_on_error=False ), call( ['umount', '--lazy', '/system-root/boot/efi'], raise_on_error=False ), call( ['umount', '--lazy', '/system-root/home'], raise_on_error=False ), call( ['umount', '--lazy', '/system-root/'], raise_on_error=False ), call(['systemctl', 'reboot']), call(['systemctl', '--force', 'reboot']) ] assert 'Reboot system: [Force Reboot]' in self._caplog.text
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 test_main(self, mock_fstab, mock_command_run, mock_configparser_items, mock_os_exists, mock_os_listdir, mock_log): def luks(device): command = Mock() command.returncode = 0 command.output = 'ext4' if device[-1] == '/dev/disk/by-label/foo': command.output = 'crypto_LUKS' return command fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_fstab.return_value = fstab_mock mock_command_run.side_effect = luks mock_os_exists.return_value = True mock_os_listdir.return_value = [ 'no_remote.repo', 'super_repo.repo', 'another.repo' ] repo_no_foo = 'hd:/?device=/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2' repo_no_bar = 'hd:/?device=/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea4' mock_configparser_items.side_effect = [[ ('name', 'Foo'), ('enabled', '1'), ('autorefresh', '0'), ('baseurl', 'https://download.foo.com/foo/repo/'), ('type', 'rpm-md') ], [('name', 'No_Foo'), ('enabled', '1'), ('autorefresh', '0'), ('baseurl', f"{repo_no_foo}"), ('path', '/'), ('keeppackages', '0')], [('name', 'No_Bar'), ('enabled', '1'), ('autorefresh', '0'), ('baseurl', f"{repo_no_bar}"), ('path', '/'), ('keeppackages', '0')]] warning_message_remote_repos = \ 'The following repositories may cause the migration to fail, as they ' \ 'may not be available during the migration' warning_message_show_repos = \ 'To see all the repositories and their urls, you can run "zypper repos --url"' with self._caplog.at_level(logging.WARNING): main() assert warning_message_remote_repos in self._caplog.text assert warning_message_show_repos in self._caplog.text
def encryption(): log = logging.getLogger(Defaults.get_migration_log_name()) fstab = Fstab() fstab.read('/etc/fstab') fstab_entries = fstab.get_devices() for fstab_entry in fstab_entries: result = Command.run( ["blkid", "-s", "TYPE", "-o", "value", fstab_entry.device] ) if result.returncode == 0: if 'LUKS' in result.output: log.warning( 'There are encrypted filesystems: {}, this may be an ' 'issue when migrating'.format(fstab_entry.device) )
def test_main_kexec_reboot(self, mock_Fstab, mock_Command_run, mock_info, mock_get_migration_config_file): fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/system-root.fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_Fstab.return_value = fstab_mock mock_get_migration_config_file.return_value = \ '../data/migration-config.yml' main() assert mock_info.called assert mock_Command_run.call_args_list == [ call(['systemctl', 'status', '-l', '--all'], raise_on_error=False), call(['umount', '--lazy', '/system-root/home'], raise_on_error=False), call(['umount', '--lazy', '/system-root/boot/efi'], raise_on_error=False), call(['umount', '--lazy', '/system-root/'], raise_on_error=False), call(['systemctl', 'reboot']) ]
def test_main_raises_and_umount_file_system( self, mock_os_listdir, mock_shutil_copy, mock_Command_run, mock_os_path_exists, mock_Fstab, mock_logger_setup, mock_update_regionsrv_setup ): fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/bind-mounted.fstab') fstab_mock.get_devices.return_value = fstab.get_devices() fstab_mock.export.side_effect = Exception mock_Fstab.return_value = fstab_mock mock_os_path_exists.return_value = True with raises(DistMigrationZypperMetaDataException): main() assert mock_Command_run.call_args_list == [ call(['ip', 'a'], raise_on_error=False), call(['ip', 'r'], raise_on_error=False), call(['cat', '/etc/resolv.conf'], raise_on_error=False), call(['cat', '/proc/net/bonding/bond*'], raise_on_error=False), call(['umount', '/system-root/sys'], raise_on_error=False), call(['umount', '/system-root/proc'], raise_on_error=False), call(['umount', '/system-root/dev'], raise_on_error=False) ]
class TestFstab(object): @fixture(autouse=True) def inject_fixtures(self, caplog): self._caplog = caplog @patch('os.path.exists') def setup(self, mock_os_path_exists): mock_os_path_exists.return_value = True self.fstab = Fstab() self.fstab.read('../data/fstab') @patch('os.path.exists') def test_read_with_skipped_entries(self, mock_os_path_exists): def skip_device(device): if '/dev/mynode' in device: return False return True mock_os_path_exists.side_effect = skip_device fstab = Fstab() with self._caplog.at_level(logging.WARNING): fstab.read('../data/fstab') assert 'Device path /dev/mynode not found and skipped' in \ self._caplog.text assert fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home/stack', device='/dev/homeboy', options='defaults') ] def test_get_devices(self): assert self.fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/foo', device='/dev/mynode', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home/stack', device='/dev/homeboy', options='defaults') ] def test_add_entry(self): fstab = Fstab() fstab.add_entry('/dev/sda', '/foo') assert fstab.get_devices() == [ fstab.fstab_entry_type(fstype='none', mountpoint='/foo', device='/dev/sda', options='defaults') ] def test_export(self): fstab = Fstab() fstab.add_entry('/dev/sda', '/foo') with patch('builtins.open', create=True) as mock_open: mock_open.return_value = MagicMock(spec=io.IOBase) fstab.export('filename') file_handle = mock_open.return_value.__enter__.return_value mock_open.assert_called_once_with('filename', 'w') assert file_handle.write.call_args_list == [ call('/dev/sda /foo none defaults 0 0\n') ]
def test_main(self, mock_path_exists, mock_is_mounted, mock_Fstab, mock_path_wipe, mock_path_create, mock_Command_run, mock_logger_setup, mock_update_migration_config_file, mock_get_migration_config_file, mock_get_system_migration_custom_config_file, mock_yaml_dump, mock_yaml_safe_load): def _is_mounted(path): if path == '/run/initramfs/isoscan': return True return False fstab = Fstab() fstab_mock = Mock() fstab_mock.read.return_value = fstab.read('../data/fstab') fstab_mock.get_devices.return_value = fstab.get_devices() mock_is_mounted.side_effect = _is_mounted mock_path_exists.side_effect = [True, True, False] mock_Fstab.return_value = fstab_mock command = Mock() command.returncode = 1 command.output = '/dev/sda1 part\n/dev/mapper/LVRoot lvm' mock_Command_run.return_value = command mock_get_system_migration_custom_config_file.return_value = \ '../data/optional-migration-config.yml' mock_get_migration_config_file.return_value = \ '../data/migration-config.yml' mock_yaml_safe_load.return_value = { 'migration_product': 'SLES/15/x86_64' } with patch('builtins.open', create=True) as mock_open: main() assert mock_update_migration_config_file.called assert mock_Command_run.call_args_list == [ call(['mount', '-o', 'remount,rw', '/run/initramfs/isoscan']), call(['lsblk', '-p', '-n', '-r', '-o', 'NAME,TYPE']), call(['vgchange', '-a', 'y']), call(['mount', '/dev/sda1', '/system-root'], raise_on_error=False), call(['umount', '/system-root'], raise_on_error=False), 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/mynode', '/system-root/foo' ]), call([ 'mount', '-o', 'defaults', '/dev/disk/by-label/foo', '/system-root/home' ]), call([ 'mount', '-o', 'defaults', '/dev/disk/by-uuid/FCF7-B051', '/system-root/boot/efi' ]), call([ 'mount', '-o', 'defaults', '/dev/homeboy', '/system-root/home/stack' ]), call([ 'mount', '-t', 'devtmpfs', 'devtmpfs', '/system-root/dev' ]), call(['mount', '-t', 'proc', 'proc', '/system-root/proc']), call(['mount', '-t', 'sysfs', 'sysfs', '/system-root/sys']) ] assert fstab_mock.add_entry.call_args_list == [ call('/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', '/system-root/', 'ext4'), call('/dev/disk/by-partuuid/3c8bd108-01', '/system-root/bar', 'ext4'), call('/dev/mynode', '/system-root/foo', 'ext4'), call('/dev/disk/by-label/foo', '/system-root/home', 'ext4'), call( '/dev/disk/by-uuid/FCF7-B051', '/system-root/boot/efi', 'vfat', ), call('/dev/homeboy', '/system-root/home/stack', 'ext4'), call('devtmpfs', '/system-root/dev'), call('/proc', '/system-root/proc'), call('sysfs', '/system-root/sys') ] fstab_mock.export.assert_called_once_with('/etc/system-root.fstab') assert mock_open.call_args_list == [ call('../data/migration-config.yml', 'r') ]
class TestFstab(object): @patch('os.path.exists') def setup(self, mock_os_path_exists): mock_os_path_exists.return_value = True self.fstab = Fstab() self.fstab.read('../data/fstab') @patch('suse_migration_services.logger.log.warning') @patch('os.path.exists') def test_read_with_skipped_entries(self, mock_os_path_exists, mock_log_warning): mock_os_path_exists.return_value = False fstab = Fstab() fstab.read('../data/fstab') mock_log_warning.assert_called_once_with( 'Device path /dev/mynode not found and skipped') assert fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults') ] def test_get_devices(self): assert self.fstab.get_devices() == [ self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/', device='/dev/disk/by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr'), self.fstab.fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device='/dev/disk/by-uuid/FCF7-B051', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/home', device='/dev/disk/by-label/foo', options='defaults'), self.fstab.fstab_entry_type( fstype='ext4', mountpoint='/bar', device='/dev/disk/by-partuuid/3c8bd108-01', options='defaults'), self.fstab.fstab_entry_type(fstype='ext4', mountpoint='/foo', device='/dev/mynode', options='defaults') ] def test_add_entry(self): fstab = Fstab() fstab.add_entry('/dev/sda', '/foo') assert fstab.get_devices() == [ fstab.fstab_entry_type(fstype='none', mountpoint='/foo', device='/dev/sda', options='defaults') ] def test_export(self): fstab = Fstab() fstab.add_entry('/dev/sda', '/foo') with patch('builtins.open', create=True) as mock_open: mock_open.return_value = MagicMock(spec=io.IOBase) fstab.export('filename') file_handle = mock_open.return_value.__enter__.return_value mock_open.assert_called_once_with('filename', 'w') assert file_handle.write.call_args_list == [ call('/dev/sda /foo none defaults 0 0\n') ]
def main(): """ DistMigration prepare for migration Prepare the migration live system to allow zypper migration to upgrade the system across major distribution versions. The zypper migration process contacts the service that provides the configured repositories on the system being migrated. The service must be one of SUSE's repository services, SCC, RMT, or SMT. This requiers information from the target system. This service makes the necessary information available inside the live system that performs the migration. """ root_path = Defaults.get_system_root_path() suse_connect_setup = os.sep.join( [root_path, 'etc', 'SUSEConnect'] ) suse_cloud_regionsrv_setup = os.sep.join( [root_path, 'etc', 'regionserverclnt.cfg'] ) hosts_setup = os.sep.join( [root_path, 'etc', 'hosts'] ) trust_anchors = os.sep.join( [root_path, 'usr', 'share', 'pki', 'trust', 'anchors'] ) if os.path.exists(suse_connect_setup): shutil.copy( suse_connect_setup, '/etc/SUSEConnect' ) if os.path.exists(suse_cloud_regionsrv_setup): shutil.copy( suse_cloud_regionsrv_setup, '/etc/regionserverclnt.cfg' ) if os.path.exists(hosts_setup): shutil.copy( hosts_setup, '/etc/hosts' ) if os.path.exists(trust_anchors): certificates = os.listdir(trust_anchors) if certificates: for cert in certificates: log.info( 'Importing certificate: {0}'.format(cert) ) shutil.copy( os.sep.join([trust_anchors, cert]), '/usr/share/pki/trust/anchors/' ) log.info('Update certificate pool') Command.run( ['update-ca-certificates'] ) zypp_metadata = os.sep.join( [root_path, 'etc', 'zypp'] ) zypp_plugins = os.sep.join( [root_path, 'usr', 'lib', 'zypp', 'plugins'] ) cloud_register_metadata = os.sep.join( [root_path, 'var', 'lib', 'cloudregister'] ) dev_mount_point = os.sep.join( [root_path, 'dev'] ) proc_mount_point = os.sep.join( [root_path, 'proc'] ) sys_mount_point = os.sep.join( [root_path, 'sys'] ) try: # log network info as network-online.target is done at this point log_network_details() log.info('Running prepare service') system_mount = Fstab() system_mount.read( Defaults.get_system_mount_info_file() ) log.info('Bind mounting /etc/zypp') Command.run( ['mount', '--bind', zypp_metadata, '/etc/zypp'] ) system_mount.add_entry( zypp_metadata, '/etc/zypp' ) log.info('Bind mounting /usr/lib/zypp/plugins') Command.run( ['mount', '--bind', zypp_plugins, '/usr/lib/zypp/plugins'] ) system_mount.add_entry( zypp_plugins, '/usr/lib/zypp/plugins' ) if os.path.exists(cloud_register_metadata): log.info('Bind mounting /var/lib/cloudregister') Path.create('/var/lib/cloudregister') Command.run( [ 'mount', '--bind', cloud_register_metadata, '/var/lib/cloudregister' ] ) log.info('Mounting kernel file systems inside {0}'.format(root_path)) Command.run( ['mount', '-t', 'devtmpfs', 'devtmpfs', dev_mount_point] ) system_mount.add_entry( 'devtmpfs', dev_mount_point ) Command.run( ['mount', '-t', 'proc', 'proc', proc_mount_point] ) system_mount.add_entry( '/proc', proc_mount_point ) Command.run( ['mount', '-t', 'sysfs', 'sysfs', sys_mount_point] ) system_mount.add_entry( 'sysfs', sys_mount_point ) system_mount.export( Defaults.get_system_mount_info_file() ) except Exception as issue: log.error( 'Preparation of zypper metadata failed with {0}'.format( issue ) ) log.info('Unmounting kernel file systems, if any') for entry in reversed(system_mount.get_devices()): Command.run( ['umount', entry.mountpoint], raise_on_error=False ) raise DistMigrationZypperMetaDataException( 'Preparation of zypper metadata failed with {0}'.format( issue ) )
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 """ try: log.info( 'Systemctl Status Information: {0}{1}'.format( os.linesep, Command.run( ['systemctl', 'status', '-l', '--all'], raise_on_error=False ).output ) ) 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 ) ) ) log.info( # reboot is performed through systemd. The call through # systemd checks if there is a kexec loaded kernel and # transparently turns 'systemctl reboot' into # 'systemctl kexec'. Thus both ways, soft and hard # reboot are managed in one call. 'Reboot system: {0}{1}'.format( os.linesep, Command.run( ['systemctl', 'reboot'] ) ) ) 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'] )