Merge pull request #20427 from ceph/wip-rm22988

ceph-volume use realpath when checking mounts

Reviewed-by: Andrew Schoen <aschoen@redhat.com>
This commit is contained in:
Andrew Schoen 2018-02-13 23:57:04 +01:00 committed by GitHub
commit 5f7c250d29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 7 deletions

View File

@ -101,6 +101,18 @@ class TestDeviceIsMounted(object):
def test_is_mounted_at_destination(self, fake_proc):
assert system.device_is_mounted('/dev/sda1', destination='/far/lib/ceph/osd/ceph-7') is False
def test_is_realpath_dev_mounted_at_destination(self, fake_proc, monkeypatch):
monkeypatch.setattr(system.os.path, 'realpath', lambda x: '/dev/sda1' if 'foo' in x else x)
result = system.device_is_mounted('/dev/maper/foo', destination='/far/lib/ceph/osd/ceph-0')
assert result is True
def test_is_realpath_path_mounted_at_destination(self, fake_proc, monkeypatch):
monkeypatch.setattr(
system.os.path, 'realpath',
lambda x: '/far/lib/ceph/osd/ceph-0' if 'symlink' in x else x)
result = system.device_is_mounted('/dev/sda1', destination='/symlink/lib/ceph/osd/ceph-0')
assert result is True
class TestGetMounts(object):

View File

@ -1,4 +1,5 @@
import errno
import logging
import os
import pwd
import platform
@ -7,6 +8,7 @@ import uuid
from ceph_volume import process
from . import as_string
logger = logging.getLogger(__name__)
# TODO: get these out of here and into a common area for others to consume
if platform.system() == 'FreeBSD':
@ -137,16 +139,40 @@ def device_is_mounted(dev, destination=None):
Check if the given device is mounted, optionally validating that a
destination exists
"""
mounts = get_mounts(devices=True)
plain_mounts = get_mounts(devices=True)
realpath_mounts = get_mounts(devices=True, realpath=True)
realpath_dev = os.path.realpath(dev) if dev.startswith('/') else dev
destination = os.path.realpath(destination) if destination else None
mounted_locations = mounts.get(dev, [])
# plain mounts
plain_dev_mounts = plain_mounts.get(dev, [])
realpath_dev_mounts = plain_mounts.get(realpath_dev, [])
# realpath mounts
plain_dev_real_mounts = realpath_mounts.get(dev, [])
realpath_dev_real_mounts = realpath_mounts.get(realpath_dev, [])
if destination:
return destination in mounted_locations
return mounted_locations != []
mount_locations = [
plain_dev_mounts,
realpath_dev_mounts,
plain_dev_real_mounts,
realpath_dev_real_mounts
]
for mounts in mount_locations:
if mounts: # we have a matching mount
if destination:
if destination in mounts:
logger.info(
'%s detected as mounted, exists at destination: %s', dev, destination
)
return True
else:
logger.info('%s was found as mounted')
return True
logger.info('%s was not found as mounted')
return False
def get_mounts(devices=False, paths=False):
def get_mounts(devices=False, paths=False, realpath=False):
"""
Create a mapping of all available system mounts so that other helpers can
detect nicely what path or device is mounted
@ -160,6 +186,9 @@ def get_mounts(devices=False, paths=False):
If ``devices`` is set to ``True`` the mapping will be a device-to-path(s),
if ``paths`` is set to ``True`` then the mapping will be
a path-to-device(s)
:param realpath: Resolve devices to use their realpaths. This is useful for
paths like LVM where more than one path can point to the same device
"""
devices_mounted = {}
paths_mounted = {}
@ -173,7 +202,10 @@ def get_mounts(devices=False, paths=False):
fields = [as_string(f) for f in line.split()]
if len(fields) < 3:
continue
device = fields[0]
if realpath:
device = os.path.realpath(fields[0]) if fields[0].startswith('/') else fields[0]
else:
device = fields[0]
path = os.path.realpath(fields[1])
# only care about actual existing devices
if not os.path.exists(device) or not device.startswith('/'):