def create_fstab(self, fstab: Fstab) -> None: """ Create etc/fstab from given Fstab object Custom fstab modifications are possible and handled in the following order: 1. Look for an optional fstab.append file which allows to append custom fstab entries to the final fstab. Once embedded the fstab.append file will be deleted 2. Look for an optional fstab.patch file which allows to patch the current contents of the fstab file with a given patch file. Once patched the fstab.patch file will be deleted 3. Look for an optional fstab.script file which is called chrooted for the purpose of updating the fstab file as appropriate. Note: There is no validation in place that checks if the script actually handles fstab or any other file in the image rootfs. Once called the fstab.script file will be deleted :param object fstab: instance of Fstab """ fstab_file = self.root_dir + '/etc/fstab' fstab_append_file = self.root_dir + '/etc/fstab.append' fstab_patch_file = self.root_dir + '/etc/fstab.patch' fstab_script_file = self.root_dir + '/etc/fstab.script' fstab.export(fstab_file) if os.path.exists(fstab_append_file): with open(fstab_file, 'a') as fstab_io: with open(fstab_append_file, 'r') as append: fstab_io.write(append.read()) Path.wipe(fstab_append_file) if os.path.exists(fstab_patch_file): Command.run( ['patch', fstab_file, fstab_patch_file] ) Path.wipe(fstab_patch_file) if os.path.exists(fstab_script_file): Command.run( ['chroot', self.root_dir, '/etc/fstab.script'] ) Path.wipe(fstab_script_file)
class TestFstab(object): @fixture(autouse=True) def inject_fixtures(self, caplog): self._caplog = caplog def setup(self): self.fstab = Fstab() with self._caplog.at_level(logging.WARNING): self.fstab.read('../data/fstab') assert format( 'Mountpoint for "LABEL=bar /home xfs defaults 0 0" ' 'in use by "LABEL=foo /home ext4 defaults 0 0", skipped' ) in self._caplog.text def test_get_devices(self): assert self.fstab.get_devices() == [ fstab_entry_type( fstype='ext4', mountpoint='/', device_path='/dev/disk/' 'by-uuid/bd604632-663b-4d4c-b5b0-8d8686267ea2', device_spec='UUID=bd604632-663b-4d4c-b5b0-8d8686267ea2', options='acl,user_xattr', dump='0', fs_passno='1'), fstab_entry_type( fstype='swap', mountpoint='swap', device_path='/dev/disk/' 'by-uuid/daa5a8c3-5c72-4343-a1d4-bb74ec4e586e', device_spec='UUID=daa5a8c3-5c72-4343-a1d4-bb74ec4e586e', options='defaults', dump='0', fs_passno='0'), fstab_entry_type(fstype='vfat', mountpoint='/boot/efi', device_path='/dev/disk/by-uuid/FCF7-B051', device_spec='UUID=FCF7-B051', options='defaults', dump='0', fs_passno='0'), fstab_entry_type(fstype='xfs', mountpoint='/boot', device_path='/dev/disk/by-label/BOOT', device_spec='LABEL=BOOT', options='defaults', dump='0', fs_passno='0'), fstab_entry_type(fstype='ext4', mountpoint='/home', device_path='/dev/disk/by-label/foo', device_spec='LABEL=foo', options='defaults', dump='0', fs_passno='0'), fstab_entry_type(fstype='ext4', mountpoint='/bar', device_path='/dev/disk/by-partuuid/3c8bd108-01', device_spec='PARTUUID=3c8bd108-01', options='defaults', dump='0', fs_passno='0'), fstab_entry_type(fstype='ext4', mountpoint='/foo', device_path='/dev/mynode', device_spec='/dev/mynode', options='defaults', dump='0', fs_passno='0') ] def test_export_and_canonical_order(self): with patch('builtins.open', create=True) as mock_open: mock_open.return_value = MagicMock(spec=io.IOBase) self.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('UUID=daa5a8c3-5c72-4343-a1d4-bb74ec4e586e swap ' 'swap defaults 0 0\n'), call('UUID=bd604632-663b-4d4c-b5b0-8d8686267ea2 / ' 'ext4 acl,user_xattr 0 1\n'), call('PARTUUID=3c8bd108-01 /bar ext4 defaults 0 0\n'), call('LABEL=BOOT /boot xfs defaults 0 0\n'), call('/dev/mynode /foo ext4 defaults 0 0\n'), call('LABEL=foo /home ext4 defaults 0 0\n'), call('UUID=FCF7-B051 /boot/efi vfat defaults 0 0\n') ]