Merge "Fix for LV mounting issue in docker containers"
This commit is contained in:
commit
3eb24b54c6
@ -39,10 +39,32 @@ class DockerExecHelper(driver.ExecuteMixin):
|
|||||||
LOG.debug("Starting container from image %s.", image_name)
|
LOG.debug("Starting container from image %s.", image_name)
|
||||||
# (aovchinnikov): --privileged is required for both samba and
|
# (aovchinnikov): --privileged is required for both samba and
|
||||||
# nfs-ganesha to actually allow access to shared folders.
|
# nfs-ganesha to actually allow access to shared folders.
|
||||||
|
#
|
||||||
|
# (aovchinnikov): To actually make docker container mount a
|
||||||
|
# logical volume created after container start-up to some location
|
||||||
|
# inside it, we must share entire /dev with it. While seemingly
|
||||||
|
# dangerous it is not and moreover this is apparently the only sane
|
||||||
|
# way to do it. The reason is when a logical volume gets created
|
||||||
|
# several new things appear in /dev: a new /dev/dm-X and a symlink
|
||||||
|
# in /dev/volume_group_name pointing to /dev/dm-X. But to be able
|
||||||
|
# to interact with /dev/dm-X, it must be already present inside
|
||||||
|
# the container's /dev i.e. it must have been -v shared during
|
||||||
|
# container start-up. So we should either precreate an unknown
|
||||||
|
# number of /dev/dm-Xs (one per LV), share them all and hope
|
||||||
|
# for the best or share the entire /dev and hope for the best.
|
||||||
|
#
|
||||||
|
# The risk of allowing a container having access to entire host's
|
||||||
|
# /dev is not as big as it seems: as long as actual share providers
|
||||||
|
# are invulnerable this does not pose any extra risks. If, however,
|
||||||
|
# share providers contain vulnerabilities then the driver does not
|
||||||
|
# provide any more possibilities for an exploitation than other
|
||||||
|
# first-party drivers.
|
||||||
|
|
||||||
cmd = ["docker", "run", "-d", "-i", "-t", "--privileged",
|
cmd = ["docker", "run", "-d", "-i", "-t", "--privileged",
|
||||||
"--name=%s" % name, '-v', "/tmp/shares:/shares", image_name]
|
"-v", "/dev:/dev", "--name=%s" % name,
|
||||||
result = self._inner_execute(cmd) or ['', 1]
|
"-v", "/tmp/shares:/shares", image_name]
|
||||||
if result[1] != '':
|
result = self._inner_execute(cmd) or ["", 1]
|
||||||
|
if result[1] != "":
|
||||||
raise exception.ManilaException(
|
raise exception.ManilaException(
|
||||||
_("Container %s has failed to start.") % name)
|
_("Container %s has failed to start.") % name)
|
||||||
LOG.info(_LI("A container has been successfully started! Its id is "
|
LOG.info(_LI("A container has been successfully started! Its id is "
|
||||||
|
@ -126,6 +126,11 @@ class ContainerShareDriver(driver.ShareDriver, driver.ExecuteMixin):
|
|||||||
["mkdir", "-m", "750", "/shares/%s" % share_name]
|
["mkdir", "-m", "750", "/shares/%s" % share_name]
|
||||||
)
|
)
|
||||||
self.storage.provide_storage(share)
|
self.storage.provide_storage(share)
|
||||||
|
lv_device = self.storage._get_lv_device(share)
|
||||||
|
self.container.execute(
|
||||||
|
server_id,
|
||||||
|
["mount", lv_device, "/shares/%s" % share_name]
|
||||||
|
)
|
||||||
location = self._get_helper(share).create_share(server_id)
|
location = self._get_helper(share).create_share(server_id)
|
||||||
return location
|
return location
|
||||||
|
|
||||||
@ -136,15 +141,30 @@ class ContainerShareDriver(driver.ShareDriver, driver.ExecuteMixin):
|
|||||||
server_id = self._get_container_name(share_server["id"])
|
server_id = self._get_container_name(share_server["id"])
|
||||||
self._get_helper(share).delete_share(server_id)
|
self._get_helper(share).delete_share(server_id)
|
||||||
|
|
||||||
self.storage.remove_storage(share)
|
self.container.execute(
|
||||||
|
server_id,
|
||||||
|
["umount", "/shares/%s" % share.share_id]
|
||||||
|
)
|
||||||
self.container.execute(
|
self.container.execute(
|
||||||
server_id,
|
server_id,
|
||||||
["rm", "-fR", "/shares/%s" % share.share_id]
|
["rm", "-fR", "/shares/%s" % share.share_id]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.storage.remove_storage(share)
|
||||||
LOG.debug("Deletion of share %s is completed!", share.share_id)
|
LOG.debug("Deletion of share %s is completed!", share.share_id)
|
||||||
|
|
||||||
def extend_share(self, share, new_size, share_server=None):
|
def extend_share(self, share, new_size, share_server=None):
|
||||||
|
server_id = self._get_container_name(share_server["id"])
|
||||||
|
self.container.execute(
|
||||||
|
server_id,
|
||||||
|
["umount", "/shares/%s" % share.share_id]
|
||||||
|
)
|
||||||
self.storage.extend_share(share, new_size, share_server)
|
self.storage.extend_share(share, new_size, share_server)
|
||||||
|
lv_device = self.storage._get_lv_device(share)
|
||||||
|
self.container.execute(
|
||||||
|
server_id,
|
||||||
|
["mount", lv_device, "/shares/%s" % share.share_id]
|
||||||
|
)
|
||||||
|
|
||||||
def ensure_share(self, context, share, share_server=None):
|
def ensure_share(self, context, share, share_server=None):
|
||||||
pass
|
pass
|
||||||
|
@ -77,24 +77,14 @@ class LVMHelper(driver.ExecuteMixin):
|
|||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
self._execute("mkfs.ext4", self._get_lv_device(share),
|
self._execute("mkfs.ext4", self._get_lv_device(share),
|
||||||
run_as_root=True)
|
run_as_root=True)
|
||||||
self._execute("mount", self._get_lv_device(share),
|
|
||||||
self._get_lv_folder(share), run_as_root=True)
|
|
||||||
self._execute("chmod", "-R", "750", self._get_lv_folder(share),
|
|
||||||
run_as_root=True)
|
|
||||||
self._execute("chown", "nobody:nogroup", self._get_lv_folder(share),
|
|
||||||
run_as_root=True)
|
|
||||||
|
|
||||||
def remove_storage(self, share):
|
def remove_storage(self, share):
|
||||||
self._execute("umount", self._get_lv_device(share), run_as_root=True)
|
|
||||||
self._execute("lvremove", "-f", "--autobackup", "n",
|
self._execute("lvremove", "-f", "--autobackup", "n",
|
||||||
self._get_lv_device(share), run_as_root=True)
|
self._get_lv_device(share), run_as_root=True)
|
||||||
|
|
||||||
def extend_share(self, share, new_size, share_server=None):
|
def extend_share(self, share, new_size, share_server=None):
|
||||||
lv_device = self._get_lv_device(share)
|
lv_device = self._get_lv_device(share)
|
||||||
lv_folder = self._get_lv_folder(share)
|
|
||||||
self._execute("umount", lv_folder, run_as_root=True)
|
|
||||||
cmd = ('lvextend', '-L', '%sG' % new_size, '-n', lv_device)
|
cmd = ('lvextend', '-L', '%sG' % new_size, '-n', lv_device)
|
||||||
self._execute(*cmd, run_as_root=True)
|
self._execute(*cmd, run_as_root=True)
|
||||||
self._execute("e2fsck", "-f", "-y", lv_device, run_as_root=True)
|
self._execute("e2fsck", "-f", "-y", lv_device, run_as_root=True)
|
||||||
self._execute('resize2fs', lv_device, run_as_root=True)
|
self._execute('resize2fs', lv_device, run_as_root=True)
|
||||||
self._execute("mount", lv_device, lv_folder, run_as_root=True)
|
|
||||||
|
@ -37,8 +37,8 @@ class DockerExecHelperTestCase(test.TestCase):
|
|||||||
self.mock_object(self.DockerExecHelper, "_inner_execute",
|
self.mock_object(self.DockerExecHelper, "_inner_execute",
|
||||||
mock.Mock(return_value=['fake_output', '']))
|
mock.Mock(return_value=['fake_output', '']))
|
||||||
uuid.uuid1 = mock.Mock(return_value='')
|
uuid.uuid1 = mock.Mock(return_value='')
|
||||||
expected = ['docker', 'run', '-d', '-i', '-t', '--privileged',
|
expected = ['docker', 'run', '-d', '-i', '-t', '--privileged', '-v',
|
||||||
'--name=manila_cifs_docker_container', '-v',
|
'/dev:/dev', '--name=manila_cifs_docker_container', '-v',
|
||||||
'/tmp/shares:/shares', 'fake_image']
|
'/tmp/shares:/shares', 'fake_image']
|
||||||
|
|
||||||
self.DockerExecHelper.start_container()
|
self.DockerExecHelper.start_container()
|
||||||
|
@ -58,6 +58,14 @@ class ContainerShareDriverTestCase(test.TestCase):
|
|||||||
# Used only to test compatibility with share manager
|
# Used only to test compatibility with share manager
|
||||||
self.share_server = "fake_share_server"
|
self.share_server = "fake_share_server"
|
||||||
|
|
||||||
|
def fake_exec_sync(self, *args, **kwargs):
|
||||||
|
kwargs['execute_arguments'].append(args)
|
||||||
|
try:
|
||||||
|
ret_val = kwargs['ret_val']
|
||||||
|
except KeyError:
|
||||||
|
ret_val = None
|
||||||
|
return ret_val
|
||||||
|
|
||||||
def test__get_helper_ok(self):
|
def test__get_helper_ok(self):
|
||||||
share = cont_fakes.fake_share(share_proto='CIFS')
|
share = cont_fakes.fake_share(share_proto='CIFS')
|
||||||
expected = protocol_helper.DockerCIFSHelper(None)
|
expected = protocol_helper.DockerCIFSHelper(None)
|
||||||
@ -125,9 +133,21 @@ class ContainerShareDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_extend_share(self):
|
def test_extend_share(self):
|
||||||
share = cont_fakes.fake_share()
|
share = cont_fakes.fake_share()
|
||||||
|
actual_arguments = []
|
||||||
|
expected_arguments = [
|
||||||
|
('manila_fake_server', ['umount', '/shares/fakeshareid']),
|
||||||
|
('manila_fake_server',
|
||||||
|
['mount', '/dev/manila_docker_volumes/fakeshareid',
|
||||||
|
'/shares/fakeshareid'])
|
||||||
|
]
|
||||||
self.mock_object(self._driver.storage, "extend_share")
|
self.mock_object(self._driver.storage, "extend_share")
|
||||||
|
self._driver.container.execute = functools.partial(
|
||||||
|
self.fake_exec_sync, execute_arguments=actual_arguments,
|
||||||
|
ret_val='')
|
||||||
|
|
||||||
self._driver.extend_share(share, 2, 'fake-server')
|
self._driver.extend_share(share, 2, {'id': 'fake-server'})
|
||||||
|
|
||||||
|
self.assertEqual(expected_arguments, actual_arguments)
|
||||||
|
|
||||||
def test_ensure_share(self):
|
def test_ensure_share(self):
|
||||||
# Does effectively nothing by design.
|
# Does effectively nothing by design.
|
||||||
|
@ -73,10 +73,6 @@ class LVMHelperTestCase(test.TestCase):
|
|||||||
('lvcreate', '-p', 'rw', '-L', '1G', '-n', 'fakeshareid',
|
('lvcreate', '-p', 'rw', '-L', '1G', '-n', 'fakeshareid',
|
||||||
'manila_docker_volumes'),
|
'manila_docker_volumes'),
|
||||||
('mkfs.ext4', '/dev/manila_docker_volumes/fakeshareid'),
|
('mkfs.ext4', '/dev/manila_docker_volumes/fakeshareid'),
|
||||||
('mount', '/dev/manila_docker_volumes/fakeshareid',
|
|
||||||
'/tmp/shares/fakeshareid'),
|
|
||||||
('chmod', '-R', '750', '/tmp/shares/fakeshareid'),
|
|
||||||
('chown', 'nobody:nogroup', '/tmp/shares/fakeshareid')
|
|
||||||
]
|
]
|
||||||
self.LVMHelper._execute = functools.partial(
|
self.LVMHelper._execute = functools.partial(
|
||||||
self.fake_exec_sync, execute_arguments=actual_arguments,
|
self.fake_exec_sync, execute_arguments=actual_arguments,
|
||||||
@ -89,7 +85,6 @@ class LVMHelperTestCase(test.TestCase):
|
|||||||
def test_remove_storage(self):
|
def test_remove_storage(self):
|
||||||
actual_arguments = []
|
actual_arguments = []
|
||||||
expected_arguments = [
|
expected_arguments = [
|
||||||
('umount', '/dev/manila_docker_volumes/fakeshareid'),
|
|
||||||
('lvremove', '-f', '--autobackup', 'n',
|
('lvremove', '-f', '--autobackup', 'n',
|
||||||
'/dev/manila_docker_volumes/fakeshareid')
|
'/dev/manila_docker_volumes/fakeshareid')
|
||||||
]
|
]
|
||||||
@ -104,13 +99,10 @@ class LVMHelperTestCase(test.TestCase):
|
|||||||
def test_extend_share(self):
|
def test_extend_share(self):
|
||||||
actual_arguments = []
|
actual_arguments = []
|
||||||
expected_arguments = [
|
expected_arguments = [
|
||||||
('umount', '/tmp/shares/fakeshareid'),
|
|
||||||
('lvextend', '-L', 'shareG', '-n',
|
('lvextend', '-L', 'shareG', '-n',
|
||||||
'/dev/manila_docker_volumes/fakeshareid'),
|
'/dev/manila_docker_volumes/fakeshareid'),
|
||||||
('e2fsck', '-f', '-y', '/dev/manila_docker_volumes/fakeshareid'),
|
('e2fsck', '-f', '-y', '/dev/manila_docker_volumes/fakeshareid'),
|
||||||
('resize2fs', '/dev/manila_docker_volumes/fakeshareid'),
|
('resize2fs', '/dev/manila_docker_volumes/fakeshareid'),
|
||||||
('mount', '/dev/manila_docker_volumes/fakeshareid',
|
|
||||||
'/tmp/shares/fakeshareid')
|
|
||||||
]
|
]
|
||||||
self.LVMHelper._execute = functools.partial(
|
self.LVMHelper._execute = functools.partial(
|
||||||
self.fake_exec_sync, execute_arguments=actual_arguments,
|
self.fake_exec_sync, execute_arguments=actual_arguments,
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- Makes docker containers actually mount logical volumes.
|
Loading…
Reference in New Issue
Block a user