From 9847796f01571dc7be332707dc935efac66ee5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Nov=C3=BD?= Date: Mon, 17 Oct 2016 19:46:57 +0200 Subject: [PATCH] Set owner of drive-audit recon cache to swift user Fixies this problem: * swift-drive-audit needs to be run by root, because only root have "umount" permission * swift-object servers typically runs as user swift * if swift-drive-audit is run by root, /var/cache/swift/drive.recon is owned by root, with 0o600 * recon middleware (inside swift-object-server) can't read this cache file: swift-object: Error reading recon cache file This patch adds "user" option to drive-audit config file. Recon cache is chowned to this user. Change-Id: Ibf20543ee690b7c5a37fabd1540fd5c0c7b638c9 --- bin/swift-drive-audit | 3 ++- doc/source/admin_guide.rst | 2 ++ etc/drive-audit.conf-sample | 1 + swift/common/utils.py | 6 +++++- test/unit/common/test_utils.py | 22 ++++++++++++++++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/bin/swift-drive-audit b/bin/swift-drive-audit index 010fa10a4f..bda4cd2af7 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 ffeb322386..c9f69f3951 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 b1d8e4d0a2..fc7f730ef3 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 e18a8bce7d..4c41a4d9dd 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 6de8859163..0b25a2bf1c 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')