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 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 execute(*cmd, **kwargs): command = ' '.join(cmd) LOG.debug('Trying to execute command: %s', command) commands = [c.strip() for c in re.split(r'\|', command)] if kwargs.get('env_variables'): LOG.debug('Env variables: {0}'.format(kwargs.get('env_variables'))) env = kwargs.pop('env_variables', copy.deepcopy(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') logged = kwargs.pop('logged', False) 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(six.moves.range(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') if six.PY2 else c 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) if logged: LOG.debug('Extended log: \nstdout:{0}\nstderr:{1}'.format( stdout, stderr)) 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)