diff --git a/swift/obj/auditor.py b/swift/obj/auditor.py index fce1d85b59..4c78d07af3 100644 --- a/swift/obj/auditor.py +++ b/swift/obj/auditor.py @@ -257,8 +257,12 @@ class ObjectAuditor(Daemon): signal.signal(signal.SIGTERM, signal.SIG_DFL) if zero_byte_fps: kwargs['zero_byte_fps'] = self.conf_zero_byte_fps - self.run_audit(**kwargs) - sys.exit() + try: + self.run_audit(**kwargs) + except Exception as e: + self.logger.error(_("ERROR: Unable to run auditing: %s") % e) + finally: + sys.exit() def audit_loop(self, parent, zbo_fps, override_devices=None, **kwargs): """Parallel audit loop""" diff --git a/test/unit/obj/test_auditor.py b/test/unit/obj/test_auditor.py index e65beab84e..e8f8a2b16a 100644 --- a/test/unit/obj/test_auditor.py +++ b/test/unit/obj/test_auditor.py @@ -487,6 +487,18 @@ class TestAuditor(unittest.TestCase): finally: auditor.diskfile.DiskFile = was_df + @mock.patch.object(auditor.ObjectAuditor, 'run_audit') + @mock.patch('os.fork', return_value=0) + def test_with_inaccessible_object_location(self, mock_os_fork, + mock_run_audit): + # Need to ensure that any failures in run_audit do + # not prevent sys.exit() from running. Otherwise we get + # zombie processes. + e = OSError('permission denied') + mock_run_audit.side_effect = e + self.auditor = auditor.ObjectAuditor(self.conf) + self.assertRaises(SystemExit, self.auditor.fork_child, self) + def test_with_tombstone(self): ts_file_path = self.setup_bad_zero_byte(with_ts=True) self.assertTrue(ts_file_path.endswith('ts'))