def test_do_build_image_retries_attach_image( self, mock_attach_file, mock_get_free_loop_device): mock_attach_file.side_effect = \ [errors.ProcessExecutionError(), errors.ProcessExecutionError(), True] free_loop_device = '/dev/loop0' mock_get_free_loop_device.return_value = free_loop_device loop_device_major_number = 7 max_loop_devices_count = 255 max_attempts = 3 filename = mock.sentinel loop_device = bu.attach_file_to_free_loop_device( filename, max_loop_devices_count=max_loop_devices_count, loop_device_major_number=loop_device_major_number, max_attempts=max_attempts) self.assertEqual(free_loop_device, loop_device) self.assertEqual( [mock.call(loop_device_major_number=loop_device_major_number, max_loop_devices_count=max_loop_devices_count)] * 3, mock_get_free_loop_device.call_args_list) self.assertEqual( [mock.call(filename, '/dev/loop0')] * 3, mock_attach_file.call_args_list)
def execute(*cmd, **kwargs): command = ' '.join(cmd) LOG.debug('Trying to execute command: %s', command) commands = [c.strip() for c in re.split(ur'\|', command)] env = os.environ env['PATH'] = '/bin:/usr/bin:/sbin:/usr/sbin' check_exit_code = kwargs.pop('check_exit_code', [0]) ignore_exit_code = False to_filename = kwargs.get('to_filename') cwd = kwargs.get('cwd') if isinstance(check_exit_code, bool): ignore_exit_code = not check_exit_code check_exit_code = [0] elif isinstance(check_exit_code, int): check_exit_code = [check_exit_code] to_file = None if to_filename: to_file = open(to_filename, 'wb') process = [] for c in commands: try: # NOTE(eli): Python's shlex implementation doesn't like unicode. # We have to convert to ascii before shlex'ing the command. # http://bugs.python.org/issue6988 encoded_command = c.encode('ascii') process.append( subprocess.Popen( shlex.split(encoded_command), env=env, stdin=(process[-1].stdout if process else None), stdout=(to_file if (len(process) == len(commands) - 1) and to_file else subprocess.PIPE), stderr=(subprocess.PIPE), cwd=cwd)) except OSError as e: raise errors.ProcessExecutionError(exit_code=1, stdout='', stderr=e, cmd=command) if len(process) >= 2: process[-2].stdout.close() #FIXME(agordeev): added sleep for preventing parted failures #TODO(agordeev): figure out the better way to be ensure that partition # information was updated properly time.sleep(1) stdout, stderr = process[-1].communicate() if not ignore_exit_code and process[-1].returncode not in check_exit_code: raise errors.ProcessExecutionError(exit_code=process[-1].returncode, stdout=stdout, stderr=stderr, cmd=command) return (stdout, stderr)
def test_make_fs_bad_swap_retry(self): # We mock utils.execute to throw an exception on first two # invocations of blkid to test the retry loop. rvs = [ None, errors.ProcessExecutionError(), None, errors.ProcessExecutionError(), None, None ] with mock.patch.object(utils, 'execute', side_effect=rvs) as mock_exec: fu.make_fs('swap', '', 'fake_label', '/dev/fake') expected_calls = 3 * [ mock.call('mkswap', '-f', '-L', 'fake_label', '/dev/fake'), mock.call('blkid', '-c', '/dev/null', '-o', 'value', '-s', 'UUID', '/dev/fake') ] self.assertEqual(mock_exec.call_args_list, expected_calls)
def test_umount_fs_error_lazy_false(self, mock_exec): mock_exec.side_effect = [ None, errors.ProcessExecutionError('message')] expected_calls = [ mock.call('mountpoint', '-q', '/fake', check_exit_code=[0]), mock.call('umount', '/fake', check_exit_code=[0]), ] self.assertRaises(errors.ProcessExecutionError, fu.umount_fs, '/fake', try_lazy_umount=False) self.assertEqual(expected_calls, mock_exec.call_args_list)
def test_umount_fs_error(self, mock_exec): mock_exec.side_effect = [ None, errors.ProcessExecutionError('message'), ('', '')] fu.umount_fs('/fake', try_lazy_umount=True) expected_calls = [ mock.call('mountpoint', '-q', '/fake', check_exit_code=[0]), mock.call('umount', '/fake', check_exit_code=[0]), mock.call('umount', '-l', '/fake', check_exit_code=[0]) ] self.assertEqual(expected_calls, mock_exec.call_args_list)
def test_do_build_image_retries_attach_image_max_attempts_exceeded( self, mock_attach_file, mock_get_free_loop_device): mock_attach_file.side_effect = errors.ProcessExecutionError() with self.assertRaises(errors.NoFreeLoopDevices): bu.attach_file_to_free_loop_device( mock.sentinel, max_loop_devices_count=255, loop_device_major_number=7, max_attempts=3) self.assertEqual(mock_attach_file.call_count, 3)
def test_make_fs_bad_swap_failure(self): # We mock utils.execute to throw an exception on invocations # of blkid (MAX_MKFS_TRIES times) to see if it fails. rvs = fu.MAX_MKFS_TRIES * [None, errors.ProcessExecutionError()] with mock.patch.object(utils, 'execute', side_effect=rvs) as mock_exec: with self.assertRaises(errors.FsUtilsError): fu.make_fs('swap', '', 'fake_label', '/dev/fake') expected_calls = 3 * [ mock.call('mkswap', '-f', '-L', 'fake_label', '/dev/fake'), mock.call('blkid', '-c', '/dev/null', '-o', 'value', '-s', 'UUID', '/dev/fake') ] self.assertEqual(mock_exec.call_args_list, expected_calls)
def test_override_config_value_fail(self, m_move, m_copy, m_upd, m_execute, m_remove, m_time): m_execute.side_effect = (['old_fake_config', ''], errors.ProcessExecutionError()) m_upd.return_value = 'fake_config' with mock.patch('six.moves.builtins.open', create=True) as mock_open: file_handle_mock = mock_open.return_value.__enter__.return_value self.assertRaises(errors.ProcessExecutionError, bu.override_lvm_config_value, 'fake_chroot', 'foo', 'bar', 'buzz', 'lvm.conf') self.assertTrue(file_handle_mock.write.called) m_copy.assert_called_once_with( 'fake_chroot/lvm.conf', 'fake_chroot/lvm.conf.bak.fake_timestamp') m_move.assert_called_once_with( 'fake_chroot/lvm.conf.bak.fake_timestamp', 'fake_chroot/lvm.conf')
def execute(*cmd, **kwargs): command = ' '.join(cmd) LOG.debug('Trying to execute command: %s', command) commands = [c.strip() for c in re.split(ur'\|', command)] env = os.environ env['PATH'] = '/bin:/usr/bin:/sbin:/usr/sbin' env['LC_ALL'] = env['LANG'] = env['LANGUAGE'] = kwargs.pop('language', 'C') attempts = kwargs.pop('attempts', 1) check_exit_code = kwargs.pop('check_exit_code', [0]) ignore_exit_code = False to_filename = kwargs.get('to_filename') cwd = kwargs.get('cwd') if isinstance(check_exit_code, bool): ignore_exit_code = not check_exit_code check_exit_code = [0] elif isinstance(check_exit_code, int): check_exit_code = [check_exit_code] to_file = None if to_filename: to_file = open(to_filename, 'wb') for attempt in reversed(xrange(attempts)): try: process = [] for c in commands: try: # NOTE(eli): Python's shlex implementation doesn't like # unicode. We have to convert to ascii before shlex'ing # the command. http://bugs.python.org/issue6988 encoded_command = c.encode('ascii') process.append( subprocess.Popen( shlex.split(encoded_command), env=env, stdin=(process[-1].stdout if process else None), stdout=(to_file if ((len(process) == len(commands) - 1) and to_file) else subprocess.PIPE), stderr=(subprocess.PIPE), cwd=cwd)) except (OSError, ValueError) as e: raise errors.ProcessExecutionError(exit_code=1, stdout='', stderr=e, cmd=command) if len(process) >= 2: process[-2].stdout.close() stdout, stderr = process[-1].communicate() if (not ignore_exit_code and process[-1].returncode not in check_exit_code): raise errors.ProcessExecutionError( exit_code=process[-1].returncode, stdout=stdout, stderr=stderr, cmd=command) return (stdout, stderr) except errors.ProcessExecutionError as e: LOG.warning('Failed to execute command: %s', e) if not attempt: raise else: time.sleep(CONF.execute_retry_delay)