def test_mdadm_stop_retry_exhausted(self, mock_sleep): device = "/dev/md/37" retries = 60 self._set_sys_path(device) self.mock_util_load_file.side_effect = iter([ "resync", "max", "proc/mdstat output", ] * retries) self.mock_util_subp.side_effect = iter([ util.ProcessExecutionError(), ] * retries) # sometimes we fail to modify sysfs attrs self.mock_util_write_file.side_effect = iter([ "", IOError()] * retries) with self.assertRaises(OSError): mdadm.mdadm_stop(device) expected_calls = [ call(["mdadm", "--manage", "--stop", device], capture=True), ] * retries self.mock_util_subp.assert_has_calls(expected_calls) expected_reads = [ call(self.sys_path + '/sync_action'), call(self.sys_path + '/sync_max'), call('/proc/mdstat'), ] * retries self.mock_util_load_file.assert_has_calls(expected_reads) expected_writes = [ call(self.sys_path + '/sync_action', content='idle'), call(self.sys_path + '/sync_max', content='0'), ] * retries self.mock_util_write_file.assert_has_calls(expected_writes)
def test_disconnect_target_disk_raises_runtime_error(self, mock_logout): """Test iscsi raises RuntimeError if we fail to logout""" sessions = [ 'curtin-53ab23ff-a887-449a-80a8-288151208091', ] connection = '10.245.168.20,16395,1' self._setup_nodes(sessions, connection) self.mock_iscsi_sessions.return_value = "\n".join(sessions) mock_logout.side_effect = util.ProcessExecutionError() with self.assertRaises(RuntimeError): iscsi.disconnect_target_disks(self.target_path) expected_calls = [] for session in sessions: (host, port, _) = connection.split(',') disconnect = self._fmt_disconnect(session, "%s:%s" % (host, port)) calls = [ mock.call(['sync']), mock.call(disconnect, capture=True, log_captured=True), mock.call(['udevadm', 'settle']), ] expected_calls.extend(calls) self.mock_subp.assert_has_calls([], any_order=True)
def test_export_armour_missingkey(self, mock_subp): key = 'DEADBEEF' mock_subp.side_effect = iter([util.ProcessExecutionError()]) expected_armour = gpg.export_armour(key) mock_subp.assert_called_with(["gpg", "--export", "--armour", key], capture=True) self.assertEqual(None, expected_armour)
def test_info_returns_partial_dictionary(self): """dasdinfo returns partial dictionary on error.""" device_id = random_device_id() self.m_subp.side_effect = ( util.ProcessExecutionError(stdout=self.info_no_serial, stderr=self.random_string(), exit_code=random.randint(1, 255), cmd=self.random_string())) expected = util.load_shell_content(self.info_no_serial) self.assertDictEqual(expected, dasd.dasdinfo(device_id))
def test_info_raise_error_if_strict(self): """dasdinfo raises ProcessEdecutionError if strict is True.""" device_id = random_device_id() self.m_subp.side_effect = ( util.ProcessExecutionError(stdout=self.random_string(), stderr=self.random_string(), exit_code=random.randint(1, 255), cmd=self.random_string())) with self.assertRaises(util.ProcessExecutionError): dasd.dasdinfo(device_id, strict=True)
def test_info_raises_on_failure(self): """dasdinfo raises if the process invocation fails.""" device_id = random_device_id() expected_stdout = self.random_string() expected_stderr = self.random_string() self.m_subp.side_effect = (util.ProcessExecutionError( stdout=expected_stdout, stderr=expected_stderr, exit_code=random.randint(1, 255), cmd=self.random_string())) with self.assertRaises(util.ProcessExecutionError): dasd.dasdinfo(device_id)
def test_sfdisk_info_returns_empty_on_subp_error(self): """verify sfdisk_info returns empty dict on subp errors.""" self.m_subp.side_effect = (util.ProcessExecutionError( stdout="", stderr="sfdisk: cannot open /dev/vdb: Permission denied", exit_code=1)) self.assertEqual({}, block.sfdisk_info(self.device)) self.assertEqual([mock.call(self.device)], self.m_get_blockdev_for_partition.call_args_list) self.assertEqual( [mock.call(['sfdisk', '--json', self.disk], capture=True)], self.m_subp.call_args_list) self.assertEqual([], self.m_load_json.call_args_list)
def test_info_returns_rawoutput_on_partial_discovery(self): """dasdinfo returns stdout, stderr on error if rawoutput is True.""" device_id = random_device_id() expected_stdout = self.random_string() expected_stderr = self.random_string() self.m_subp.side_effect = ( util.ProcessExecutionError(stdout=expected_stdout, stderr=expected_stderr, exit_code=random.randint(1, 255), cmd=self.random_string())) (stdout, stderr) = dasd.dasdinfo(device_id, rawoutput=True) self.assertEqual(expected_stdout, stdout) self.assertEqual(expected_stderr, stderr)
def run(self): for cmdname in sorted(self.commands.keys()): cmd = self.commands[cmdname] if not cmd: continue cur_res = events.ReportEventStack( name=cmdname, description="running '%s'" % ' '.join(cmd), parent=self.reportstack, level="DEBUG") env = self.env.copy() env['CURTIN_REPORTSTACK'] = cur_res.fullname shell = not isinstance(cmd, list) with util.LogTimer(LOG.debug, cmdname): with cur_res: try: sp = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, shell=shell) except OSError as e: LOG.warn("%s command failed", cmdname) raise util.ProcessExecutionError(cmd=cmd, reason=e) output = b"" while True: data = sp.stdout.read(1) if not data and sp.poll() is not None: break self.write(data) output += data rc = sp.returncode if rc != 0: LOG.warn("%s command failed", cmdname) raise util.ProcessExecutionError( stdout=output, stderr="", exit_code=rc, cmd=cmd)
def _extract_root_layered_fsimage(image_stack, target): mp_base = tempfile.mkdtemp() mps = [] try: # Create a mount point for each image file and mount the image try: for img in image_stack: mp = os.path.join(mp_base, os.path.basename(img) + ".dir") os.mkdir(mp) util.subp(['mount', '-o', 'loop,ro', img, mp], capture=True) mps.insert(0, mp) except util.ProcessExecutionError as e: LOG.error("Failed to mount '%s' for extraction: %s", img, e) raise e # Prepare if len(mps) == 1: root_dir = mps[0] else: # Multiple image files, merge them with an overlay and do the copy root_dir = os.path.join(mp_base, "root.dir") os.mkdir(root_dir) try: util.subp([ 'mount', '-t', 'overlay', 'overlay', '-o', 'lowerdir=' + ':'.join(mps), root_dir ], capture=True) mps.append(root_dir) except util.ProcessExecutionError as e: LOG.error("overlay mount to %s failed: %s", root_dir, e) raise e copy_to_target(root_dir, target) finally: umount_err_mps = [] for mp in reversed(mps): try: util.subp(['umount', mp], capture=True) except util.ProcessExecutionError as e: LOG.error("can't unmount %s: %e", mp, e) umount_err_mps.append(mp) if umount_err_mps: raise util.ProcessExecutionError("Failed to umount: %s", ", ".join(umount_err_mps)) shutil.rmtree(mp_base)
def test_mount_fstab_data_does_not_swallow_subp_exception(self, m_subp): """verify that subp exception gets raised. The implementation there could/should change to raise the ProcessExecutionError directly. Currently raises a RuntimeError.""" my_error = util.ProcessExecutionError(stdout="", stderr="BOOM", exit_code=4) m_subp.side_effect = my_error mp = self.tmp_path("my-mountpoint") with self.assertRaisesRegexp(RuntimeError, r"Mount failed.*"): block_meta.mount_fstab_data(block_meta.FstabData( device="/dev/disk1", path="/var"), target=mp) # dir should be created before call to subp failed. self.assertTrue(os.path.isdir(mp))
def test_recv_key_retry_works(self, mock_under_subp, mock_sleep): key = 'DEADBEEF' keyserver = 'keyserver.ubuntu.com' nr_calls = 2 mock_under_subp.side_effect = iter([ util.ProcessExecutionError(), # 1 ("", ""), ]) gpg.recv_key(key, keyserver, retries=[1]) print("_subp calls: %s" % mock_under_subp.call_args_list) print("sleep calls: %s" % mock_sleep.call_args_list) expected_calls = nr_calls * [ call(["gpg", "--keyserver", keyserver, "--recv", key], capture=True)] mock_under_subp.assert_has_calls(expected_calls) mock_sleep.assert_has_calls([call(1)])
def test_recv_key_retry_raises(self, mock_under_subp, mock_sleep): key = 'DEADBEEF' keyserver = 'keyserver.ubuntu.com' retries = (1, 2, 5, 10) nr_calls = 5 mock_under_subp.side_effect = iter([ util.ProcessExecutionError()] * nr_calls) with self.assertRaises(ValueError): gpg.recv_key(key, keyserver, retries=retries) print("_subp calls: %s" % mock_under_subp.call_args_list) print("sleep calls: %s" % mock_sleep.call_args_list) expected_calls = nr_calls * [ call(["gpg", "--keyserver", keyserver, "--recv", key], capture=True)] mock_under_subp.assert_has_calls(expected_calls) expected_calls = [call(1), call(2), call(5), call(10)] mock_sleep.assert_has_calls(expected_calls)
def test_mdadm_stop_retry_sysfs_write_fail(self, mock_sleep): device = "/dev/md126" self._set_sys_path(device) self.mock_util_load_file.side_effect = iter([ "resync", "max", "proc/mdstat output", "idle", "0", ]) self.mock_util_subp.side_effect = iter([ util.ProcessExecutionError(), ("mdadm stopped %s" % device, ''), ]) # sometimes we fail to modify sysfs attrs self.mock_util_write_file.side_effect = iter([ "", # write to sync_action OK IOError(), # write to sync_max FAIL ]) mdadm.mdadm_stop(device) expected_calls = [ call(["mdadm", "--manage", "--stop", device], capture=True), call(["mdadm", "--manage", "--stop", device], capture=True) ] self.mock_util_subp.assert_has_calls(expected_calls) expected_reads = [ call(self.sys_path + '/sync_action'), call(self.sys_path + '/sync_max'), call('/proc/mdstat'), call(self.sys_path + '/sync_action'), call(self.sys_path + '/sync_max'), ] self.mock_util_load_file.assert_has_calls(expected_reads) expected_writes = [ call(self.sys_path + '/sync_action', content='idle'), ] self.mock_util_write_file.assert_has_calls(expected_writes)
def _raise_pexec_error(*args, **kwargs): raise util.ProcessExecutionError()
def test_udevadm_info_path_not_exists(self, m_subp): """ udevadm_info raises ProcessExecutionError for invalid path value""" mypath = self.random_string() m_subp.side_effect = util.ProcessExecutionError() with self.assertRaises(util.ProcessExecutionError): udevadm_info(mypath)
def doraise(*args, **kwargs): raise util.ProcessExecutionError("foo")
def test_zkey_supported_returns_false_zkey_error(self, m_kmod, m_subp): m_subp.side_effect = (util.ProcessExecutionError( stdout=self.random_string(), stderr=self.random_string(), exit_code=2)) self.assertFalse(block.zkey_supported())
def test_check_vtoc_signature_returns_false_with_no_sig(self): self.m_subp.side_effect = iter( [util.ProcessExecutionError(stdout="", stderr="", exit_code=1)]) self.assertFalse(block.check_vtoc_signature(self.blockdev))
def setUp(self): super(TestPartTableSignature, self).setUp() self.add_patch('curtin.util.subp', 'm_subp') self.m_subp.side_effect = iter( [util.ProcessExecutionError(stdout="", stderr="", exit_code=1)])
def test__returns_none_on_error(self): self.mock_subp.side_effect = util.ProcessExecutionError() self.assertIsNone(curthooks.get_flash_kernel_pkgs('arm64', False)) self.mock_subp.assert_called_with( ['list-flash-kernel-packages'], capture=True)