def test_target_is_ubuntu_core_noncore_target(self): self.target = self.tmp_dir() non_core_path = os.path.join(self.target, 'curtin') util.ensure_dir(non_core_path) self.assertTrue(os.path.isdir(non_core_path)) is_core = curthooks.target_is_ubuntu_core(self.target) self.assertFalse(is_core)
def clear_install_log(logfile): """Clear the installation log, so no previous installation is present.""" util.ensure_dir(os.path.dirname(logfile)) try: open(logfile, 'w').close() except Exception: pass
def test_collect_logs_main_sources_config_from_save_install_config(self): """collect_logs_main uses /root/curtin-install-cfg.yaml config.""" savefile = self.tmp_path('curtin-install-cfg.log', _dir=self.new_root) write_file(savefile, 'install:\n log_file: /tmp/savefile.log\n') packdir = self.tmp_path('configs', _dir=self.new_root) ensure_dir(packdir) unusedcfg = os.path.join(packdir, 'config-001.yaml') write_file(unusedcfg, 'install:\n log_file: /tmp/unused.log\n') utcnow = datetime.utcnow() datestr = utcnow.strftime('%Y-%m-%d-%H-%M') tardir = self.tmp_path('curtin-logs-%s' % datestr, _dir=self.tmpdir) curtin_config = self.tmp_path('curtin-config', _dir=tardir) self.assertEqual('/curtin/configs', collect_logs.CURTIN_PACK_CONFIG_DIR) self.add_patch('curtin.commands.collect_logs.SAVE_INSTALL_CONFIG', '_idir', new=savefile, autospec=None) self.add_patch('curtin.commands.collect_logs.CURTIN_PACK_CONFIG_DIR', '_cdir', new=packdir, autospec=None) self.add_patch('shutil.rmtree', 'm_rmtree') with mock.patch('sys.stderr'): with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: with self.assertRaises(SystemExit) as context_manager: m_dt.utcnow.return_value = utcnow collect_logs.collect_logs_main(FakeArgs('my.tar')) self.assertEqual('0', str(context_manager.exception)) expected_cfg = {'install': {'log_file': '/tmp/savefile.log'}} with open(curtin_config, 'r') as f: self.assertEqual(expected_cfg, json.loads(f.read()))
def test_curtin_error_unmount_doesnt_lose_exception(self): """Confirm unmount:disable skips unmounting, keeps exception""" working_dir = self.tmp_path('working', _dir=self.new_root) ensure_dir(working_dir) write_file(self.logfile, 'old log') # Providing two dd images raises an error, set unmount: disabled myargs = FakeArgs( config={'install': {'log_file': self.logfile, 'unmount': 'disabled'}}, source=['dd-raw:https://localhost/raw_images/centos-6-3.img', 'dd-raw:https://localhost/cant/provide/two/images.img'], reportstack=FakeReportStack()) self.add_patch( 'curtin.commands.collect_logs.create_log_tarfile', 'm_tar') self.add_patch( 'curtin.commands.install.copy_install_log', 'm_copy_log') self.add_patch('curtin.util.do_umount', 'm_umount') rv = 42 with self.assertRaises(Exception): rv = install.cmd_install(myargs) # make sure install.cmd_install does not return a value, but Exception self.assertEqual(42, rv) self.assertEqual(0, self.m_umount.call_count) self.assertEqual(1, self.m_copy_log.call_count)
def _setup_nodes(self, sessions, connection): # setup iscsi_nodes dir (<fakeroot>/etc/iscsi/nodes) with content for s in sessions: sdir = os.path.join(self.iscsi_nodes, s) connpath = os.path.join(sdir, connection) util.ensure_dir(sdir) util.write_file(connpath, content="")
def test_target_is_ubuntu_core(self): self.target = self.tmp_dir() ubuntu_core_path = os.path.join(self.target, 'system-data', 'var/lib/snapd') util.ensure_dir(ubuntu_core_path) self.assertTrue(os.path.isdir(ubuntu_core_path)) is_core = curthooks.target_is_ubuntu_core(self.target) self.assertTrue(is_core)
def setUp(self): super(TestBlockIscsiDisconnect, self).setUp() self.add_patch('curtin.block.iscsi.util.subp', 'mock_subp') self.add_patch('curtin.block.iscsi.iscsiadm_sessions', 'mock_iscsi_sessions') # fake target_root + iscsi nodes dir self.target_path = self.tmp_dir() self.iscsi_nodes = os.path.join(self.target_path, 'etc/iscsi/nodes') util.ensure_dir(self.iscsi_nodes)
def setUp(self): super(TestCollectLogs, self).setUp() self.new_root = self.tmp_dir() self.add_patch('curtin.util.subp', 'mock_subp') self.mock_subp.return_value = ('', '') self.tmpdir = self.tmp_path('mytemp', _dir=self.new_root) ensure_dir(self.tmpdir) # Create it because we mock mkdtemp self.add_patch('tempfile.mkdtemp', 'm_mkdtemp', return_value=self.tmpdir)
def test_target_dir_by_default_is_under_workd(self): """WorkingDir does not require target in config.""" tmp_d = self.tmp_dir() work_d = self.tmp_path("work_d", tmp_d) ensure_dir(work_d) with mock.patch("curtin.commands.install.tempfile.mkdtemp", return_value=work_d) as m_mkdtemp: wd = install.WorkingDir({}) self.assertEqual(1, m_mkdtemp.call_count) self.assertTrue(wd.target.startswith(work_d + "/"))
def _enable_loaders(bootid): efi_path = 'boot/efi/EFI' target_efi_path = os.path.join(self.target, efi_path) loaders = [ os.path.join(target_efi_path, bootid, 'shimx64.efi'), os.path.join(target_efi_path, 'BOOT', 'BOOTX64.EFI'), os.path.join(target_efi_path, bootid, 'grubx64.efi'), ] for loader in loaders: util.ensure_dir(os.path.dirname(loader)) with open(loader, 'w+') as fh: fh.write('\n')
def test_prefer_existing_bootx_loader_with_no_shim(self): # touch all loaders in target filesystem loaders = self._possible_loaders()[1:] for loader in loaders: tloader = os.path.join(self.target, loader) util.ensure_dir(os.path.dirname(tloader)) with open(tloader, 'w+') as fh: fh.write('\n') found = install_grub.find_efi_loader(self.target, self.bootid) self.assertTrue( found.endswith(os.path.join(self.efi_path, 'BOOT', 'BOOTX64.EFI')))
def prepare_grub_dir(target, grub_cfg): util.ensure_dir(os.path.dirname(target_path(target, grub_cfg))) # LP: #1179940 . The 50-cloudig-settings.cfg file is written by the cloud # images build and defines/override some settings. Disable it. ci_cfg = target_path( target, os.path.join(os.path.dirname(grub_cfg), "50-cloudimg-settings.cfg")) if os.path.exists(ci_cfg): LOG.debug('grub: moved %s out of the way', ci_cfg) shutil.move(ci_cfg, ci_cfg + '.disabled')
def setUp(self): super(TestCreateTar, self).setUp() self.new_root = self.tmp_dir() self.utcnow = datetime.utcnow() self.tardir = 'curtin-logs-%s' % self.utcnow.strftime('%Y-%m-%d-%H-%M') self.add_patch('curtin.commands.collect_logs._collect_system_info', 'm_sys_info') self.tmpdir = self.tmp_path('mytemp', _dir=self.new_root) ensure_dir(self.tmpdir) # Create it because we mock mkdtemp self.add_patch('tempfile.mkdtemp', 'm_mkdtemp', return_value=self.tmpdir)
def test_target_dir_with_content_raises_error(self): """WorkingDir raises ValueError on populated target_d.""" tmp_d = self.tmp_dir() work_d = self.tmp_path("work_d", tmp_d) target_d = self.tmp_path("target_d", tmp_d) ensure_dir(work_d) ensure_dir(target_d) write_file(self.tmp_path("somefile.txt", target_d), "sometext") with mock.patch("curtin.commands.install.tempfile.mkdtemp", return_value=work_d): with self.assertRaises(ValueError): install.WorkingDir({'install': {'target': target_d}})
def test_prefer_shim_loader(self): # touch loaders in target filesystem loaders = self._possible_loaders() for loader in loaders: tloader = os.path.join(self.target, loader) util.ensure_dir(os.path.dirname(tloader)) with open(tloader, 'w+') as fh: fh.write('\n') found = install_grub.find_efi_loader(self.target, self.bootid) self.assertTrue( found.endswith( os.path.join(self.efi_path, self.bootid, 'shimx64.efi')))
def test_target_dir_may_exist(self): """WorkingDir supports existing empty target directory.""" tmp_d = self.tmp_dir() work_d = self.tmp_path("work_d", tmp_d) target_d = self.tmp_path("target_d", tmp_d) ensure_dir(work_d) ensure_dir(target_d) with mock.patch("curtin.commands.install.tempfile.mkdtemp", return_value=work_d) as m_mkdtemp: workingdir = install.WorkingDir({'install': {'target': target_d}}) self.assertEqual(1, m_mkdtemp.call_count) self.assertEqual(target_d, workingdir.target) self.assertEqual(target_d, workingdir.env().get('TARGET_MOUNT_POINT'))
def test_curtin_error_copies_config_and_error_tarfile_defaults(self): """On curtin error, install error_tarfile is created with all logs. Curtin config, install log and error_tarfile are copied into target. """ working_dir = self.tmp_path('working', _dir=self.new_root) ensure_dir(working_dir) target_dir = self.tmp_path('target', _dir=working_dir) write_file(self.logfile, 'old log') # Providing two dd images raises an error myargs = FakeArgs( config={'install': {'log_file': self.logfile}}, source=['dd-raw:https://localhost/raw_images/centos-6-3.img', 'dd-raw:https://localhost/cant/provide/two/images.img'], reportstack=FakeReportStack()) self.add_patch( 'curtin.commands.collect_logs.create_log_tarfile', 'm_tar') self.add_patch( 'curtin.commands.install.copy_install_log', 'm_copy_log') self.add_patch( 'curtin.commands.install.tempfile.mkdtemp', 'm_mkdtemp') self.m_mkdtemp.return_value = working_dir with self.assertRaises(ValueError) as context_manager: install.cmd_install(myargs) self.assertEqual( 'You may not use more than one disk image', str(context_manager.exception)) expected_cfg = copy.deepcopy(install.CONFIG_BUILTIN) expected_cfg['install']['log_file'] = self.logfile expected_cfg['proxy'] = {} expected_cfg['sources'] = { '00_cmdline': { 'type': 'dd-raw', 'uri': 'https://localhost/raw_images/centos-6-3.img'}, '01_cmdline': { 'type': 'dd-raw', 'uri': 'https://localhost/cant/provide/two/images.img'}} expected_cfg['write_files'] = { 'curtin_install_cfg': { 'owner': 'root:root', 'permissions': '0400', 'path': '/root/curtin-install-cfg.yaml', 'content': config.dump_config(expected_cfg)}} # Call create_log_tarfile to collect error logs. self.assertEqual( [mock.call('/var/log/curtin/curtin-error-logs.tar', expected_cfg)], self.m_tar.call_args_list) self.assertEqual( [mock.call(self.logfile, target_dir, '/root/curtin-install.log')], self.m_copy_log.call_args_list)
def populate_dir(path, files): if not os.path.exists(path): os.makedirs(path) ret = [] for (name, content) in files.items(): p = os.path.sep.join([path, name]) util.ensure_dir(os.path.dirname(p)) with open(p, "wb") as fp: if isinstance(content, util.binary_type): fp.write(content) else: fp.write(content.encode('utf-8')) fp.close() ret.append(p) return ret
def __init__(self, config): top_d = tempfile.mkdtemp() state_d = os.path.join(top_d, 'state') scratch_d = os.path.join(top_d, 'scratch') for p in (state_d, scratch_d): os.mkdir(p) target_d = config.get('install', {}).get('target') if not target_d: target_d = os.path.join(top_d, 'target') try: util.ensure_dir(target_d) except OSError as e: raise ValueError( "Unable to create target directory '%s': %s" % (target_d, e)) if os.listdir(target_d) != []: raise ValueError( "Provided target dir '%s' was not empty." % target_d) netconf_f = os.path.join(state_d, 'network_config') netstate_f = os.path.join(state_d, 'network_state') interfaces_f = os.path.join(state_d, 'interfaces') config_f = os.path.join(state_d, 'config') fstab_f = os.path.join(state_d, 'fstab') with open(config_f, "w") as fp: json.dump(config, fp) # just touch these files to make sure they exist for f in (interfaces_f, config_f, fstab_f, netconf_f, netstate_f): with open(f, "ab") as fp: pass self.scratch = scratch_d self.target = target_d self.top = top_d self.interfaces = interfaces_f self.netconf = netconf_f self.netstate = netstate_f self.fstab = fstab_f self.config = config self.config_file = config_f
def test_collect_logs_main_sources_config_from_pack_configs(self): """collect_logs_main sources all configs from /curtin/configs dir.""" savefile = self.tmp_path('absentinstall.log', _dir=self.new_root) packdir = self.tmp_path('configs', _dir=self.new_root) utcnow = datetime.utcnow() datestr = utcnow.strftime('%Y-%m-%d-%H-%M') tardir = self.tmp_path('curtin-logs-%s' % datestr, _dir=self.tmpdir) ensure_dir(packdir) cfg1 = os.path.join(packdir, 'config-001.yaml') cfg2 = os.path.join(packdir, 'config-002.yaml') write_file(cfg1, 'install:\n log_file: /tmp/my.log\n') write_file(cfg2, 'install:\n post_files: [/tmp/post.log]\n') self.assertEqual('/curtin/configs', collect_logs.CURTIN_PACK_CONFIG_DIR) self.add_patch('curtin.commands.collect_logs.SAVE_INSTALL_CONFIG', '_idir', new=savefile, autospec=None) self.add_patch('curtin.commands.collect_logs.CURTIN_PACK_CONFIG_DIR', '_cdir', new=packdir, autospec=None) self.add_patch('shutil.rmtree', 'm_rmtree') with mock.patch('sys.stderr'): with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: with self.assertRaises(SystemExit) as context_manager: m_dt.utcnow.return_value = utcnow collect_logs.collect_logs_main(FakeArgs('my.tar')) self.assertEqual('0', str(context_manager.exception)) self.assertEqual(['config-001.yaml', 'config-002.yaml'], sorted(os.listdir(packdir))) curtin_config = self.tmp_path('curtin-config', _dir=tardir) # Config parts are merged with CONFIG_BUILTIN expected_cfg = copy.deepcopy(CONFIG_BUILTIN) expected_cfg['install'] = { 'log_file': '/tmp/my.log', 'post_files': ['/tmp/post.log', '/tmp/my.log'], 'error_tarfile': '/var/log/curtin/curtin-error-logs.tar' } with open(curtin_config, 'r') as f: self.assertEqual(expected_cfg, json.loads(f.read()))
def test_curthooks_cloud_config_remove_disabled(self, mock_handle_cc): self.target = self.tmp_dir() uc_cloud = os.path.join(self.target, 'system-data', 'etc/cloud') cc_disabled = os.path.join(uc_cloud, 'cloud-init.disabled') cc_path = os.path.join(uc_cloud, 'cloud.cfg.d') util.ensure_dir(uc_cloud) util.write_file(cc_disabled, content="# disable cloud-init\n") cfg = { 'cloudconfig': { 'file1': { 'content': "Hello World!\n", } } } self.assertTrue(os.path.exists(cc_disabled)) curthooks.ubuntu_core_curthooks(cfg, target=self.target) mock_handle_cc.assert_called_with(cfg.get('cloudconfig'), base_dir=cc_path) self.assertFalse(os.path.exists(cc_disabled))
def setUp(self): super(TestReplaceGrubCmdlineLinuxDefault, self).setUp() self.target = self.tmp_dir() self.grubconf = "/etc/default/grub" self.target_grubconf = paths.target_path(self.target, self.grubconf) util.ensure_dir(os.path.dirname(self.target_grubconf))