diff --git a/swift/common/utils.py b/swift/common/utils.py index dd9377dbfb..c7d67ec286 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -2566,17 +2566,19 @@ def dump_recon_cache(cache_dict, cache_file, logger, lock_timeout=2): pass for cache_key, cache_value in cache_dict.items(): put_recon_cache_entry(cache_entry, cache_key, cache_value) + tf = None try: with NamedTemporaryFile(dir=os.path.dirname(cache_file), delete=False) as tf: tf.write(json.dumps(cache_entry) + '\n') renamer(tf.name, cache_file, fsync=False) finally: - try: - os.unlink(tf.name) - except OSError as err: - if err.errno != errno.ENOENT: - raise + if tf is not None: + try: + os.unlink(tf.name) + except OSError as err: + if err.errno != errno.ENOENT: + raise except (Exception, Timeout): logger.exception(_('Exception dumping recon cache')) diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index dcc24042ba..2d77794af3 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -1216,6 +1216,29 @@ class TestUtils(unittest.TestCase): finally: rmtree(testdir_base) + def test_dump_recon_cache_permission_denied(self): + testdir_base = mkdtemp() + testcache_file = os.path.join(testdir_base, 'cache.recon') + + class MockLogger(object): + def __init__(self): + self._excs = [] + + def exception(self, message): + _junk, exc, _junk = sys.exc_info() + self._excs.append(exc) + + logger = MockLogger() + try: + submit_dict = {'key1': {'value1': 1, 'value2': 2}} + with mock.patch( + 'swift.common.utils.NamedTemporaryFile', + side_effect=IOError(13, 'Permission Denied')): + utils.dump_recon_cache(submit_dict, testcache_file, logger) + self.assertIsInstance(logger._excs[0], IOError) + finally: + rmtree(testdir_base) + def test_get_logger(self): sio = StringIO() logger = logging.getLogger('server')