diff --git a/bin/swift-drive-audit b/bin/swift-drive-audit index 010fa10a..bda4cd2a 100755 --- a/bin/swift-drive-audit +++ b/bin/swift-drive-audit @@ -208,7 +208,8 @@ if __name__ == '__main__': total_errors += count recon_file = recon_cache_path + "/drive.recon" dump_recon_cache(recon_errors, recon_file, logger) - dump_recon_cache({'drive_audit_errors': total_errors}, recon_file, logger) + dump_recon_cache({'drive_audit_errors': total_errors}, recon_file, logger, + set_owner=conf.get("user", "swift")) if unmounts == 0: logger.info("No drives were unmounted") diff --git a/doc/source/admin_guide.rst b/doc/source/admin_guide.rst index ffeb3223..c9f69f39 100644 --- a/doc/source/admin_guide.rst +++ b/doc/source/admin_guide.rst @@ -264,6 +264,8 @@ settings: ================== ============== =========================================== Option Default Description ------------------ -------------- ------------------------------------------- +user swift Drop privileges to this user for non-root + tasks log_facility LOG_LOCAL0 Syslog log facility log_level INFO Log level device_dir /srv/node Directory devices are mounted under diff --git a/etc/drive-audit.conf-sample b/etc/drive-audit.conf-sample index b1d8e4d0..fc7f730e 100644 --- a/etc/drive-audit.conf-sample +++ b/etc/drive-audit.conf-sample @@ -1,4 +1,5 @@ [drive-audit] +# user = swift # device_dir = /srv/node # # You can specify default log routing here if you want: diff --git a/swift/common/utils.py b/swift/common/utils.py index e18a8bce..4c41a4d9 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -3037,13 +3037,15 @@ def put_recon_cache_entry(cache_entry, key, item): cache_entry[key] = item -def dump_recon_cache(cache_dict, cache_file, logger, lock_timeout=2): +def dump_recon_cache(cache_dict, cache_file, logger, lock_timeout=2, + set_owner=None): """Update recon cache values :param cache_dict: Dictionary of cache key/value pairs to write out :param cache_file: cache file to update :param logger: the logger to use to log an encountered error :param lock_timeout: timeout (in seconds) + :param set_owner: Set owner of recon cache file """ try: with lock_file(cache_file, lock_timeout, unlink=False) as cf: @@ -3062,6 +3064,8 @@ def dump_recon_cache(cache_dict, cache_file, logger, lock_timeout=2): with NamedTemporaryFile(dir=os.path.dirname(cache_file), delete=False) as tf: tf.write(json.dumps(cache_entry) + '\n') + if set_owner: + os.chown(tf.name, pwd.getpwnam(set_owner).pw_uid, -1) renamer(tf.name, cache_file, fsync=False) finally: if tf is not None: diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index 6de88591..0b25a2bf 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -1377,6 +1377,28 @@ class TestUtils(unittest.TestCase): finally: rmtree(testdir_base) + def test_dump_recon_cache_set_owner(self): + testdir_base = mkdtemp() + testcache_file = os.path.join(testdir_base, 'cache.recon') + logger = utils.get_logger(None, 'server', log_route='server') + try: + submit_dict = {'key1': {'value1': 1, 'value2': 2}} + + _ret = lambda: None + _ret.pw_uid = 100 + _mock_getpwnam = MagicMock(return_value=_ret) + _mock_chown = mock.Mock() + + with patch('os.chown', _mock_chown), \ + patch('pwd.getpwnam', _mock_getpwnam): + utils.dump_recon_cache(submit_dict, testcache_file, + logger, set_owner="swift") + + _mock_getpwnam.assert_called_once_with("swift") + self.assertEqual(_mock_chown.call_args[0][1], 100) + finally: + rmtree(testdir_base) + def test_dump_recon_cache_permission_denied(self): testdir_base = mkdtemp() testcache_file = os.path.join(testdir_base, 'cache.recon')