Convert ext filesystem resizes to privsep.

This patch introduces the first code in the privsep directory which
_does_not_ run with escalated premissions. This is a requirement because
the privsep code has a restricted python path when executing. This
pattern will be used for other methods which are only sometimes
escalated.

Change-Id: Ie09e40d6476dcabda2d599e96701d419e3e8bdf0
blueprint: hurrah-for-privsep
This commit is contained in:
Michael Still 2017-11-02 16:16:12 +11:00
parent 3cec0cb584
commit cc33bdb239
3 changed files with 45 additions and 23 deletions

View File

@ -18,10 +18,14 @@ Helpers for filesystem related routines.
"""
from oslo_concurrency import processutils
from oslo_log import log as logging
import nova.privsep
LOG = logging.getLogger(__name__)
@nova.privsep.sys_admin_pctxt.entrypoint
def mount(fstype, device, mountpoint, options):
mount_cmd = ['mount']
@ -123,3 +127,24 @@ def remove_device_maps(device):
def get_filesystem_type(device):
return processutils.execute('blkid', '-o', 'value', '-s', 'TYPE', device,
check_exit_code=[0, 2])
@nova.privsep.sys_admin_pctxt.entrypoint
def resize2fs(image, check_exit_code):
unprivileged_resize2fs(image, check_exit_code)
# NOTE(mikal): this method is deliberately not wrapped in a privsep entrypoint
def unprivileged_resize2fs(image, check_exit_code):
try:
processutils.execute('e2fsck',
'-fp',
image,
check_exit_code=[0, 1, 2])
except processutils.ProcessExecutionError as exc:
LOG.debug("Checking the file system with e2fsck has failed, "
"the resize will be aborted. (%s)", exc)
else:
processutils.execute('resize2fs',
image,
check_exit_code=check_exit_code)

View File

@ -59,7 +59,7 @@ class APITestCase(test.NoDBTestCase):
self.assertTrue(api.is_image_extendable(image))
mock_exec.assert_called_once_with('e2label', imgfile)
@mock.patch.object(utils, 'execute', autospec=True)
@mock.patch('oslo_concurrency.processutils.execute', autospec=True)
def test_resize2fs_success(self, mock_exec):
imgfile = tempfile.NamedTemporaryFile()
self.addCleanup(imgfile.close)
@ -70,16 +70,24 @@ class APITestCase(test.NoDBTestCase):
[mock.call('e2fsck',
'-fp',
imgfile,
check_exit_code=[0, 1, 2],
run_as_root=False),
check_exit_code=[0, 1, 2]),
mock.call('resize2fs',
imgfile,
check_exit_code=False,
run_as_root=False)])
check_exit_code=False)])
@mock.patch.object(utils, 'execute', autospec=True,
side_effect=processutils.ProcessExecutionError(
"fs error"))
@mock.patch('oslo_concurrency.processutils.execute')
@mock.patch('nova.privsep.fs.resize2fs')
def test_resize2fs_success_as_root(self, mock_resize, mock_exec):
imgfile = tempfile.NamedTemporaryFile()
self.addCleanup(imgfile.close)
api.resize2fs(imgfile, run_as_root=True)
mock_exec.assert_not_called()
mock_resize.assert_called()
@mock.patch('oslo_concurrency.processutils.execute', autospec=True,
side_effect=processutils.ProcessExecutionError("fs error"))
def test_resize2fs_e2fsck_fails(self, mock_exec):
imgfile = tempfile.NamedTemporaryFile()
self.addCleanup(imgfile.close)
@ -88,8 +96,7 @@ class APITestCase(test.NoDBTestCase):
mock_exec.assert_called_once_with('e2fsck',
'-fp',
imgfile,
check_exit_code=[0, 1, 2],
run_as_root=False)
check_exit_code=[0, 1, 2])
@mock.patch.object(api, 'can_resize_image', autospec=True,
return_value=True)

View File

@ -121,20 +121,10 @@ def mkfs(os_type, fs_label, target, run_as_root=True, specified_fs=None):
def resize2fs(image, check_exit_code=False, run_as_root=False):
try:
utils.execute('e2fsck',
'-fp',
image,
check_exit_code=[0, 1, 2],
run_as_root=run_as_root)
except processutils.ProcessExecutionError as exc:
LOG.debug("Checking the file system with e2fsck has failed, "
"the resize will be aborted. (%s)", exc)
if run_as_root:
nova.privsep.fs.resize2fs(image, check_exit_code)
else:
utils.execute('resize2fs',
image,
check_exit_code=check_exit_code,
run_as_root=run_as_root)
nova.privsep.fs.unprivileged_resize2fs(image, check_exit_code)
def get_disk_size(path):