def test_both_clean_up(self, mock_stat, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Not enough space, clean up of both caches required mock_stat.return_value.st_dev = 1 mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.side_effect = [ mock.Mock(f_frsize=1, f_bavail=1), mock.Mock(f_frsize=1, f_bavail=2), mock.Mock(f_frsize=1, f_bavail=1024) ] cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_with('master_dir') self.assertEqual(3, mock_statvfs.call_count) self.mock_first_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 1)) self.mock_second_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 2)) mock_stat_calls_expected = [mock.call('master_dir'), mock.call('first_cache_dir'), mock.call('second_cache_dir')] mock_statvfs_calls_expected = [mock.call('master_dir'), mock.call('master_dir'), mock.call('master_dir')] self.assertEqual(mock_stat_calls_expected, mock_stat.mock_calls) self.assertEqual(mock_statvfs_calls_expected, mock_statvfs.mock_calls)
def test_one_clean_up(self, mock_stat, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Not enough space, first cache clean up is enough mock_stat.return_value.st_dev = 1 mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.side_effect = [ mock.Mock(f_frsize=1, f_bavail=1), mock.Mock(f_frsize=1, f_bavail=1024) ] cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_with('master_dir') self.assertEqual(2, mock_statvfs.call_count) self.mock_first_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 1)) self.assertFalse(self.mock_second_cache.return_value.clean_up.called) # Since we are using generator expression in clean_up_caches, stat on # second cache wouldn't be called if we got enough free space on # cleaning up the first cache. mock_stat_calls_expected = [mock.call('master_dir'), mock.call('first_cache_dir')] mock_statvfs_calls_expected = [mock.call('master_dir'), mock.call('master_dir')] self.assertEqual(mock_stat_calls_expected, mock_stat.mock_calls) self.assertEqual(mock_statvfs_calls_expected, mock_statvfs.mock_calls)
def test_clean_up_another_fs(self, mock_stat, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Not enough space, need to cleanup second cache mock_stat.side_effect = [mock.Mock(st_dev=1), mock.Mock(st_dev=2), mock.Mock(st_dev=1)] mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.side_effect = [ mock.Mock(f_frsize=1, f_bavail=1), mock.Mock(f_frsize=1, f_bavail=1024) ] cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_with('master_dir') self.assertEqual(2, mock_statvfs.call_count) self.mock_second_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 1)) self.assertFalse(self.mock_first_cache.return_value.clean_up.called) # Since first cache exists on a different partition, it wouldn't be # considered for cleanup. mock_stat_calls_expected = [mock.call('master_dir'), mock.call('first_cache_dir'), mock.call('second_cache_dir')] mock_statvfs_calls_expected = [mock.call('master_dir'), mock.call('master_dir')] self.assertEqual(mock_stat_calls_expected, mock_stat.mock_calls) self.assertEqual(mock_statvfs_calls_expected, mock_statvfs.mock_calls)
def test_no_clean_up(self, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Enough space found - no clean up mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.return_value = mock.Mock(f_frsize=1, f_bavail=1024) cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_once_with('master_dir') self.assertFalse(self.mock_first_cache.return_value.clean_up.called) self.assertFalse(self.mock_second_cache.return_value.clean_up.called) mock_statvfs.assert_called_once_with('master_dir')
def fetch_images(ctx, cache, images_info): """Check for available disk space and fetch images using ImageCache. :param ctx: context :param cache: ImageCache instance to use for fetching :param images_info: list of tuples (image uuid, destination path) :raises: InstanceDeployFailure if unable to find enough disk space """ try: image_cache.clean_up_caches(ctx, cache.master_dir, images_info) except exception.InsufficientDiskSpace as e: raise exception.InstanceDeployFailure(reason=e) # NOTE(dtantsur): This code can suffer from race condition, # if disk space is used between the check and actual download. # This is probably unavoidable, as we can't control other # (probably unrelated) processes for uuid, path in images_info: cache.fetch_image(uuid, path, ctx=ctx)
def fetch_images(ctx, cache, images_info, force_raw=True): """Check for available disk space and fetch images using ImageCache. :param ctx: context :param cache: ImageCache instance to use for fetching :param images_info: list of tuples (image href, destination path) :param force_raw: boolean value, whether to convert the image to raw format :raises: InstanceDeployFailure if unable to find enough disk space """ try: image_cache.clean_up_caches(ctx, cache.master_dir, images_info) except exception.InsufficientDiskSpace as e: raise exception.InstanceDeployFailure(reason=e) # NOTE(dtantsur): This code can suffer from race condition, # if disk space is used between the check and actual download. # This is probably unavoidable, as we can't control other # (probably unrelated) processes for href, path in images_info: cache.fetch_image(href, path, ctx=ctx, force_raw=force_raw)
def test_clean_up_another_fs(self, mock_stat, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Not enough space, need to cleanup second cache mock_stat.side_effect = [ mock.Mock(st_dev=1), mock.Mock(st_dev=2), mock.Mock(st_dev=1) ] mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.side_effect = [ mock.Mock(f_frsize=1, f_bavail=1), mock.Mock(f_frsize=1, f_bavail=1024) ] cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_with('master_dir') self.assertEqual(2, mock_statvfs.call_count) self.mock_second_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 1)) self.assertFalse(self.mock_first_cache.return_value.clean_up.called) # Since first cache exists on a different partition, it wouldn't be # considered for cleanup. mock_stat_calls_expected = [ mock.call('master_dir'), mock.call('first_cache_dir'), mock.call('second_cache_dir') ] mock_statvfs_calls_expected = [ mock.call('master_dir'), mock.call('master_dir') ] self.assertEqual(mock_stat_calls_expected, mock_stat.mock_calls) self.assertEqual(mock_statvfs_calls_expected, mock_statvfs.mock_calls)
def test_one_clean_up(self, mock_stat, mock_image_service, mock_statvfs, cache_cleanup_list_mock): # Not enough space, first cache clean up is enough mock_stat.return_value.st_dev = 1 mock_show = mock_image_service.return_value.show mock_show.return_value = dict(size=42) mock_statvfs.side_effect = [ mock.MagicMock(f_frsize=1, f_bavail=1, spec_set=['f_frsize', 'f_bavail']), mock.MagicMock(f_frsize=1, f_bavail=1024, spec_set=['f_frsize', 'f_bavail']) ] cache_cleanup_list_mock.__iter__.return_value = self.cache_cleanup_list image_cache.clean_up_caches(None, 'master_dir', [('uuid', 'path')]) mock_show.assert_called_once_with('uuid') mock_statvfs.assert_called_with('master_dir') self.assertEqual(2, mock_statvfs.call_count) self.mock_first_cache.return_value.clean_up.assert_called_once_with( amount=(42 - 1)) self.assertFalse(self.mock_second_cache.return_value.clean_up.called) # Since we are using generator expression in clean_up_caches, stat on # second cache wouldn't be called if we got enough free space on # cleaning up the first cache. mock_stat_calls_expected = [ mock.call('master_dir'), mock.call('first_cache_dir') ] mock_statvfs_calls_expected = [ mock.call('master_dir'), mock.call('master_dir') ] self.assertEqual(mock_stat_calls_expected, mock_stat.mock_calls) self.assertEqual(mock_statvfs_calls_expected, mock_statvfs.mock_calls)