Move kpartx calls to privsep.
The same pattern as before. Change-Id: Ia97d7023523208f834cb088bf290b0f3c01016bc blueprint: hurrah-for-privsep
This commit is contained in:
parent
c7dae4e19b
commit
b12f0a6026
|
@ -2,10 +2,6 @@
|
||||||
# This file should be owned by (and only-writeable by) the root user
|
# This file should be owned by (and only-writeable by) the root user
|
||||||
|
|
||||||
[Filters]
|
[Filters]
|
||||||
# nova/virt/disk/mount/api.py: 'kpartx', '-a', device
|
|
||||||
# nova/virt/disk/mount/api.py: 'kpartx', '-d', device
|
|
||||||
kpartx: CommandFilter, kpartx, root
|
|
||||||
|
|
||||||
# nova/virt/xenapi/vm_utils.py: tune2fs, -O ^has_journal, part_path
|
# nova/virt/xenapi/vm_utils.py: tune2fs, -O ^has_journal, part_path
|
||||||
# nova/virt/xenapi/vm_utils.py: tune2fs, -j, partition_path
|
# nova/virt/xenapi/vm_utils.py: tune2fs, -j, partition_path
|
||||||
tune2fs: CommandFilter, tune2fs, root
|
tune2fs: CommandFilter, tune2fs, root
|
||||||
|
|
|
@ -107,3 +107,13 @@ def nbd_connect(device, image):
|
||||||
@nova.privsep.sys_admin_pctxt.entrypoint
|
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||||
def nbd_disconnect(device):
|
def nbd_disconnect(device):
|
||||||
return processutils.execute('qemu-nbd', '-d', device)
|
return processutils.execute('qemu-nbd', '-d', device)
|
||||||
|
|
||||||
|
|
||||||
|
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||||
|
def create_device_maps(device):
|
||||||
|
return processutils.execute('kpartx', '-a', device)
|
||||||
|
|
||||||
|
|
||||||
|
@nova.privsep.sys_admin_pctxt.entrypoint
|
||||||
|
def remove_device_maps(device):
|
||||||
|
return processutils.execute('kpartx', '-d', device)
|
||||||
|
|
|
@ -36,13 +36,6 @@ class MountTestCase(test.NoDBTestCase):
|
||||||
mount.map_dev()
|
mount.map_dev()
|
||||||
return mount
|
return mount
|
||||||
|
|
||||||
@mock.patch('nova.utils.trycmd')
|
|
||||||
def _test_map_dev_with_trycmd(self, partition, trycmd):
|
|
||||||
trycmd.return_value = [None, None]
|
|
||||||
mount = self._test_map_dev(partition)
|
|
||||||
self.assertEqual(1, trycmd.call_count) # don't care about args
|
|
||||||
return mount
|
|
||||||
|
|
||||||
def _exists_effect(self, data):
|
def _exists_effect(self, data):
|
||||||
def exists_effect(filename):
|
def exists_effect(filename):
|
||||||
try:
|
try:
|
||||||
|
@ -72,36 +65,42 @@ class MountTestCase(test.NoDBTestCase):
|
||||||
self.assertFalse(mount.mapped)
|
self.assertFalse(mount.mapped)
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
def test_map_dev_good(self, exists):
|
@mock.patch('nova.privsep.fs.create_device_maps',
|
||||||
exists.side_effect = self._exists_effect({
|
return_value=(None, None))
|
||||||
|
def test_map_dev_good(self, mock_create_maps, mock_exists):
|
||||||
|
mock_exists.side_effect = self._exists_effect({
|
||||||
ORIG_DEVICE: True,
|
ORIG_DEVICE: True,
|
||||||
AUTOMAP_PARTITION: False,
|
AUTOMAP_PARTITION: False,
|
||||||
MAP_PARTITION: [False, True]})
|
MAP_PARTITION: [False, True]})
|
||||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
mount = self._test_map_dev(PARTITION)
|
||||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 2)
|
self._check_calls(mock_exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 2)
|
||||||
self.assertEqual("", mount.error)
|
self.assertEqual("", mount.error)
|
||||||
self.assertTrue(mount.mapped)
|
self.assertTrue(mount.mapped)
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
def test_map_dev_error(self, exists):
|
@mock.patch('nova.privsep.fs.create_device_maps',
|
||||||
exists.side_effect = self._exists_effect({
|
return_value=(None, None))
|
||||||
|
def test_map_dev_error(self, mock_create_maps, mock_exists):
|
||||||
|
mock_exists.side_effect = self._exists_effect({
|
||||||
ORIG_DEVICE: True,
|
ORIG_DEVICE: True,
|
||||||
AUTOMAP_PARTITION: False,
|
AUTOMAP_PARTITION: False,
|
||||||
MAP_PARTITION: False})
|
MAP_PARTITION: False})
|
||||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
mount = self._test_map_dev(PARTITION)
|
||||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION],
|
self._check_calls(mock_exists, [ORIG_DEVICE, AUTOMAP_PARTITION],
|
||||||
api.MAX_FILE_CHECKS + 1)
|
api.MAX_FILE_CHECKS + 1)
|
||||||
self.assertNotEqual("", mount.error)
|
self.assertNotEqual("", mount.error)
|
||||||
self.assertFalse(mount.mapped)
|
self.assertFalse(mount.mapped)
|
||||||
|
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
def test_map_dev_error_then_pass(self, exists):
|
@mock.patch('nova.privsep.fs.create_device_maps',
|
||||||
exists.side_effect = self._exists_effect({
|
return_value=(None, None))
|
||||||
|
def test_map_dev_error_then_pass(self, mock_create_maps, mock_exists):
|
||||||
|
mock_exists.side_effect = self._exists_effect({
|
||||||
ORIG_DEVICE: True,
|
ORIG_DEVICE: True,
|
||||||
AUTOMAP_PARTITION: False,
|
AUTOMAP_PARTITION: False,
|
||||||
MAP_PARTITION: [False, False, True]})
|
MAP_PARTITION: [False, False, True]})
|
||||||
mount = self._test_map_dev_with_trycmd(PARTITION)
|
mount = self._test_map_dev(PARTITION)
|
||||||
self._check_calls(exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 3)
|
self._check_calls(mock_exists, [ORIG_DEVICE, AUTOMAP_PARTITION], 3)
|
||||||
self.assertEqual("", mount.error)
|
self.assertEqual("", mount.error)
|
||||||
self.assertTrue(mount.mapped)
|
self.assertTrue(mount.mapped)
|
||||||
|
|
||||||
|
|
|
@ -215,9 +215,10 @@ class TestVirtDisk(test.NoDBTestCase):
|
||||||
@mock.patch('nova.privsep.fs.loopremove')
|
@mock.patch('nova.privsep.fs.loopremove')
|
||||||
@mock.patch('nova.privsep.fs.umount')
|
@mock.patch('nova.privsep.fs.umount')
|
||||||
@mock.patch('nova.privsep.fs.nbd_disconnect')
|
@mock.patch('nova.privsep.fs.nbd_disconnect')
|
||||||
|
@mock.patch('nova.privsep.fs.remove_device_maps')
|
||||||
def test_lxc_teardown_container(
|
def test_lxc_teardown_container(
|
||||||
self, mock_nbd_disconnect, mock_umount, mock_loopremove,
|
self, mock_remove_maps, mock_nbd_disconnect, mock_umount,
|
||||||
mock_exist):
|
mock_loopremove, mock_exist):
|
||||||
|
|
||||||
def proc_mounts(mount_point):
|
def proc_mounts(mount_point):
|
||||||
mount_points = {
|
mount_points = {
|
||||||
|
@ -239,13 +240,12 @@ class TestVirtDisk(test.NoDBTestCase):
|
||||||
mock_umount.reset_mock()
|
mock_umount.reset_mock()
|
||||||
|
|
||||||
disk_api.teardown_container('/mnt/loop/part')
|
disk_api.teardown_container('/mnt/loop/part')
|
||||||
expected_commands += [
|
|
||||||
('kpartx', '-d', '/dev/loop0')
|
|
||||||
]
|
|
||||||
mock_loopremove.assert_has_calls([mock.call('/dev/loop0')])
|
mock_loopremove.assert_has_calls([mock.call('/dev/loop0')])
|
||||||
mock_loopremove.reset_mock()
|
mock_loopremove.reset_mock()
|
||||||
mock_umount.assert_has_calls([mock.call('/dev/mapper/loop0p1')])
|
mock_umount.assert_has_calls([mock.call('/dev/mapper/loop0p1')])
|
||||||
mock_umount.reset_mock()
|
mock_umount.reset_mock()
|
||||||
|
mock_remove_maps.assert_has_calls([mock.call('/dev/loop0')])
|
||||||
|
mock_remove_maps.reset_mock()
|
||||||
|
|
||||||
disk_api.teardown_container('/mnt/nbd/nopart')
|
disk_api.teardown_container('/mnt/nbd/nopart')
|
||||||
expected_commands += [
|
expected_commands += [
|
||||||
|
@ -259,12 +259,13 @@ class TestVirtDisk(test.NoDBTestCase):
|
||||||
disk_api.teardown_container('/mnt/nbd/part')
|
disk_api.teardown_container('/mnt/nbd/part')
|
||||||
expected_commands += [
|
expected_commands += [
|
||||||
('blockdev', '--flushbufs', '/dev/nbd15'),
|
('blockdev', '--flushbufs', '/dev/nbd15'),
|
||||||
('kpartx', '-d', '/dev/nbd15'),
|
|
||||||
]
|
]
|
||||||
mock_nbd_disconnect.assert_has_calls([mock.call('/dev/nbd15')])
|
mock_nbd_disconnect.assert_has_calls([mock.call('/dev/nbd15')])
|
||||||
mock_umount.assert_has_calls([mock.call('/dev/mapper/nbd15p1')])
|
mock_umount.assert_has_calls([mock.call('/dev/mapper/nbd15p1')])
|
||||||
mock_nbd_disconnect.reset_mock()
|
mock_nbd_disconnect.reset_mock()
|
||||||
mock_umount.reset_mock()
|
mock_umount.reset_mock()
|
||||||
|
mock_remove_maps.assert_has_calls([mock.call('/dev/nbd15')])
|
||||||
|
mock_remove_maps.reset_mock()
|
||||||
|
|
||||||
# NOTE(thomasem): Not adding any commands in this case, because we're
|
# NOTE(thomasem): Not adding any commands in this case, because we're
|
||||||
# not expecting an additional umount for LocalBlockImages. This is to
|
# not expecting an additional umount for LocalBlockImages. This is to
|
||||||
|
|
|
@ -23,7 +23,6 @@ from oslo_utils import importutils
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova.i18n import _
|
from nova.i18n import _
|
||||||
import nova.privsep.fs
|
import nova.privsep.fs
|
||||||
from nova import utils
|
|
||||||
from nova.virt.image import model as imgmodel
|
from nova.virt.image import model as imgmodel
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
@ -200,8 +199,7 @@ class Mount(object):
|
||||||
# Note kpartx can output warnings to stderr and succeed
|
# Note kpartx can output warnings to stderr and succeed
|
||||||
# Also it can output failures to stderr and "succeed"
|
# Also it can output failures to stderr and "succeed"
|
||||||
# So we just go on the existence of the mapped device
|
# So we just go on the existence of the mapped device
|
||||||
_out, err = utils.trycmd('kpartx', '-a', self.device,
|
_out, err = nova.privsep.fs.create_device_maps(self.device)
|
||||||
run_as_root=True, discard_warnings=True)
|
|
||||||
|
|
||||||
@loopingcall.RetryDecorator(
|
@loopingcall.RetryDecorator(
|
||||||
max_retry_count=MAX_FILE_CHECKS - 1,
|
max_retry_count=MAX_FILE_CHECKS - 1,
|
||||||
|
@ -241,7 +239,7 @@ class Mount(object):
|
||||||
return
|
return
|
||||||
LOG.debug("Unmap dev %s", self.device)
|
LOG.debug("Unmap dev %s", self.device)
|
||||||
if self.partition and not self.automapped:
|
if self.partition and not self.automapped:
|
||||||
utils.execute('kpartx', '-d', self.device, run_as_root=True)
|
nova.privsep.fs.remove_device_maps(self.device)
|
||||||
self.mapped = False
|
self.mapped = False
|
||||||
self.automapped = False
|
self.automapped = False
|
||||||
|
|
||||||
|
|
|
@ -956,9 +956,7 @@ def _make_partition(session, dev, partition_start, partition_end):
|
||||||
partition_path = utils.make_dev_path(dev, partition=1)
|
partition_path = utils.make_dev_path(dev, partition=1)
|
||||||
if session.is_local_connection:
|
if session.is_local_connection:
|
||||||
# Need to refresh the partitions
|
# Need to refresh the partitions
|
||||||
utils.trycmd('kpartx', '-a', dev_path,
|
nova.privsep.fs.create_device_maps(dev_path)
|
||||||
run_as_root=True,
|
|
||||||
discard_warnings=True)
|
|
||||||
|
|
||||||
# Sometimes the partition gets created under /dev/mapper, depending
|
# Sometimes the partition gets created under /dev/mapper, depending
|
||||||
# on the setup in dom0.
|
# on the setup in dom0.
|
||||||
|
|
|
@ -10,6 +10,6 @@ upgrade:
|
||||||
internal functionality using privsep.
|
internal functionality using privsep.
|
||||||
- |
|
- |
|
||||||
The following commands are no longer required to be listed in your rootwrap
|
The following commands are no longer required to be listed in your rootwrap
|
||||||
configuration: cat; chown; cryptsetup; dd; losetup; lvcreate; lvremove;
|
configuration: cat; chown; cryptsetup; dd; kpartx; losetup; lvcreate;
|
||||||
lvs; mkdir; mount; nova-idmapshift; ploop; prl_disk_tool; qemu-nbd;
|
lvremove; lvs; mkdir; mount; nova-idmapshift; ploop; prl_disk_tool;
|
||||||
readlink; shred; tee; touch; umount; vgs; and xend.
|
qemu-nbd; readlink; shred; tee; touch; umount; vgs; and xend.
|
||||||
|
|
Loading…
Reference in New Issue