Change in vdsm[master]: hsm: Add refresh device verb

frolland at redhat.com frolland at redhat.com
Sun Mar 22 14:53:47 UTC 2015


Hello Fred Rolland,

I'd like you to do a code review.  Please visit

    https://gerrit.ovirt.org/39007

to review the following change.

Change subject: hsm: Add refresh device verb
......................................................................

hsm: Add refresh device verb

This command calls the multipath-resize and the returns
the device size.
multipath-resize resizes online multipath device after a LUN
was resized on the storage server.

Example output:

    $ vdsClient -s 0 refreshDevice 1IET_00070009
        size = '53687091200'

    $ vdsClient -s 0 refreshDevice
    Error using command: Wrong number of arguments provided, expecting 1
    (1 required) got 0

    refreshDevice
        <GUID>
        Refresh multipath device - update the device size after it was
        resized on the storage server

Change-Id: I4d66fdedf2cfdb113d07f5cd3d54adf0255d27f7
Relates-To: https://bugzilla.redhat.com/609689
Signed-off-by: Fred Rolland <frolland at redhat.com>
---
M client/vdsClient.py
M lib/vdsm/constants.py.in
M vdsm/API.py
M vdsm/rpc/BindingXMLRPC.py
M vdsm/rpc/Bridge.py
M vdsm/rpc/vdsmapi-schema.json
M vdsm/storage/hsm.py
M vdsm/storage/multipath.py
M vdsm/sudoers.vdsm.in
9 files changed, 100 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/39007/1

diff --git a/client/vdsClient.py b/client/vdsClient.py
index 07dbaa2..47cf383 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -722,6 +722,16 @@
         pp.pprint(devices['devList'])
         return 0, ''
 
+    def refreshDevice(self, args):
+        validateArgTypes(args, [str], requiredArgsNumber=1)
+        guid = args[0]
+        res = self.s.refreshDevice(guid)
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        del res['status']
+        printDict(res, self.pretty)
+        return 0, ''
+
     def getDevicesVisibility(self, args):
         devList = args[0].split(',')
         res = self.s.getDevicesVisibility(devList, {})
@@ -2209,6 +2219,11 @@
                            'List of all block devices (optionally - matching '
                            'storageType).'
                            )),
+        'refreshDevice': (serv.refreshDevice,
+                          ('<GUID>',
+                           'Refresh multipath device - update the device size'
+                           ' after it was resized on the storage server'
+                           )),
         'getDevicesVisibility': (serv.getDevicesVisibility,
                                  ('<devlist>',
                                   'Get visibility of each device listed'
diff --git a/lib/vdsm/constants.py.in b/lib/vdsm/constants.py.in
index 89bdebd..b23b441 100644
--- a/lib/vdsm/constants.py.in
+++ b/lib/vdsm/constants.py.in
@@ -164,3 +164,4 @@
 
 EXT_CURL_IMG_WRAP = '@LIBEXECDIR@/curl-img-wrap'
 EXT_FC_SCAN = '@LIBEXECDIR@/fc-scan'
+EXT_MULTIPATH_RESIZE = '@LIBEXECDIR@/multipath-resize'
diff --git a/vdsm/API.py b/vdsm/API.py
index ba99911..a53d42c 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -1612,6 +1612,9 @@
     def getDeviceList(self, storageType=None):
         return self._irs.getDeviceList(storageType)
 
+    def refreshDevice(self, guid):
+        return self._irs.refreshDevice(guid)
+
     def getDevicesVisibility(self, guidList):
         return self._irs.getDevicesVisibility(guidList)
 
diff --git a/vdsm/rpc/BindingXMLRPC.py b/vdsm/rpc/BindingXMLRPC.py
index b92fbb0..1483736 100644
--- a/vdsm/rpc/BindingXMLRPC.py
+++ b/vdsm/rpc/BindingXMLRPC.py
@@ -965,6 +965,10 @@
         api = API.Global()
         return api.getDeviceList(storageType)
 
+    def refreshDevice(self, guid, options=None):
+        api = API.Global()
+        return api.refreshDevice(guid)
+
     def devicesGetVisibility(self, guids, options=None):
         api = API.Global()
         return api.getDevicesVisibility(guids)
@@ -1119,6 +1123,7 @@
                 (self.stopMonitoringDomain, 'stopMonitoringDomain'),
                 (self.vgsGetList, 'getVGList'),
                 (self.devicesGetList, 'getDeviceList'),
+                (self.refreshDevice, 'refreshDevice'),
                 (self.devicesGetVisibility, 'getDevicesVisibility'),
                 (self.storageServerConnectionRefsAcquire,
                  'storageServer_ConnectionRefs_acquire'),
diff --git a/vdsm/rpc/Bridge.py b/vdsm/rpc/Bridge.py
index 8dc4a21..15a2b1e 100644
--- a/vdsm/rpc/Bridge.py
+++ b/vdsm/rpc/Bridge.py
@@ -401,6 +401,7 @@
     'Host_getCapabilities': {'ret': Host_getCapabilities_Ret},
     'Host_getConnectedStoragePools': {'ret': 'poollist'},
     'Host_getDeviceList': {'ret': 'devList'},
+    'Host_refreshDevice': {'ret': 'size'},
     'Host_getDevicesVisibility': {'ret': 'visible'},
     'Host_getExternalVMs': {'ret': 'vmList'},
     'Host_getHardwareInfo': {'ret': 'info'},
diff --git a/vdsm/rpc/vdsmapi-schema.json b/vdsm/rpc/vdsmapi-schema.json
index 47440a4..fd3952d 100644
--- a/vdsm/rpc/vdsmapi-schema.json
+++ b/vdsm/rpc/vdsmapi-schema.json
@@ -1476,6 +1476,22 @@
  'returns': ['BlockDeviceInfo']}
 
 ##
+# @Host.refreshDevice:
+#
+# Refresh multipath device and return the size after refresh.
+#
+# @guid:  A block device GUID
+#
+# Returns:
+# The size in bytes of the device after refresh
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'Host', 'name': 'refreshDevice'},
+ 'data': {'guid': ['UUID']},
+  'returns': 'str'}
+
+##
 # @DeviceVisibilityMap:
 #
 # A mapping of boolean values indexed by block device GUID.
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index c0ac3a1..d5ba6e8 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -2060,6 +2060,23 @@
         return devices
 
     @public
+    def refreshDevice(self, guid, options=None):
+        """
+        Calls multipath.resize with specified device guid
+        and returns the size after the resize
+
+        :param guid: Device UUID to refresh size.
+        :type guid: UUID
+        :param options: unused
+        :returns: dictionary with one item :size
+        :rtype: dict
+        """
+        multipath.resize(guid)
+        dmid = devicemapper.getDmId(guid)
+        devicesize = multipath.getDeviceSize(dmid)
+        return dict(size=str(devicesize))
+
+    @public
     def getDevicesVisibility(self, guids, options=None):
         """
         Check which of the luns with specified guids are visible
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index f12f798..8752c36 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -31,6 +31,8 @@
 
 from vdsm import constants
 from vdsm import utils
+from vdsm.config import config
+from vdsm.infra import zombiereaper
 import hba
 import misc
 import iscsi
@@ -51,6 +53,10 @@
                              )
 
 
+class Error(Exception):
+    """ multipath operation failed """
+
+
 def rescan():
     """
     Forces multipath daemon to rescan the list of available devices and
@@ -67,6 +73,40 @@
     misc.execCmd([constants.EXT_MULTIPATH], sudo=True)
 
 
+def resize(guid):
+    """
+    In case the LUN was increased on storage server, in order to see the
+    changes it is needed to rescan the device path and resize the multipath
+    map.
+
+    This method calls multipath-resize tool which will perform the following:
+        - Perform scsi scan of the device paths
+        - Resize the multipath map
+
+    SCSI scan is a blocking operation, so it is needed to run in external tool.
+    The call will block up to scsi_rescan_maximal_timeout (30 seconds by
+    default).
+    Raises multipath.Error if operation times out or multipath-resize failed.
+    TODO: move to supervdsm when zombiereaper is functional there.
+    """
+    timeout = config.getint('irs', 'scsi_rescan_maximal_timeout')
+    log.debug("Resizing device %r", guid)
+    proc = utils.execCmd([constants.EXT_MULTIPATH_RESIZE, guid], sudo=True,
+                         sync=False, execCmdLogger=log)
+    try:
+        proc.wait(timeout)
+    finally:
+        if proc.returncode is None:
+            zombiereaper.autoReapPID(proc.pid)
+            raise Error("Timeout resizing device %r (pid=%s)"
+                        % (guid, proc.pid))
+        if proc.returncode != 0:
+            stderr = proc.stderr.read(512)
+            raise Error("Error resizing device %r: %r"
+                        % (guid, stderr))
+    log.debug("Resizing device %r finished", guid)
+
+
 def deduceType(a, b):
     if a == b:
         return a
diff --git a/vdsm/sudoers.vdsm.in b/vdsm/sudoers.vdsm.in
index da88ff2..716d153 100644
--- a/vdsm/sudoers.vdsm.in
+++ b/vdsm/sudoers.vdsm.in
@@ -27,7 +27,8 @@
     @MULTIPATH_PATH@, \
     @SETSID_PATH@ @IONICE_PATH@ -c ? -n ? @SU_PATH@ vdsm -s /bin/sh -c /usr/libexec/vdsm/spmprotect.sh*, \
     @SERVICE_PATH@ vdsmd *, \
-    @REBOOT_PATH@ -f
+    @REBOOT_PATH@ -f, \
+    @LIBEXECDIR@/multipath-resize
 
 vdsm  ALL=(ALL) NOPASSWD: VDSM_LIFECYCLE, VDSM_STORAGE
 Defaults:vdsm !requiretty


-- 
To view, visit https://gerrit.ovirt.org/39007
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4d66fdedf2cfdb113d07f5cd3d54adf0255d27f7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Freddy Rolland <frolland at redhat.com>
Gerrit-Reviewer: Fred Rolland <frolland at redhat.com>


More information about the vdsm-patches mailing list