Change in vdsm[master]: [wip] drbd: initial implementation

fsimonce at redhat.com fsimonce at redhat.com
Thu Apr 4 11:11:42 UTC 2013


Federico Simoncelli has uploaded a new change for review.

Change subject: [wip] drbd: initial implementation
......................................................................

[wip] drbd: initial implementation

Change-Id: I33bb867ba6c7cfca54d31334554cb37db11aeeea
Signed-off-by: Federico Simoncelli <fsimonce at redhat.com>
---
M client/vdsClient.py
M configure.ac
M lib/vdsm/constants.py.in
M vdsm.spec.in
M vdsm/storage/Makefile.am
A vdsm/storage/drbd.py
M vdsm/storage/hsm.py
M vdsm/storage/lvm.py
M vdsm/storage/storage_exception.py
M vdsm/sudoers.vdsm.in
10 files changed, 530 insertions(+), 12 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/85/13585/1

diff --git a/client/vdsClient.py b/client/vdsClient.py
index 1da7d5f..9e9fb2e 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -1676,6 +1676,56 @@
 
         return status['status']['code'], status['status']['message']
 
+    def createReplicatedDevice(self, args):
+        dev = self.s.createReplicatedDevice(*args)
+        if dev['status']['code']:
+            return dev['status']['code'], dev['status']['message']
+        return 0, dev['uuid']
+
+    def getReplicatedResourcesList(self, args):
+        res = self.s.getReplicatedResourcesList()
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        for res in res['resList']:
+            print res
+        return 0, ''
+
+    def getReplicatedResourceInfo(self, args):
+        rdUUID = args[0]
+        res = self.s.getReplicatedResourceInfo(rdUUID)
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        for key, value in res['resInfo'].items():
+            print key, "=", value
+        return 0, ''
+
+    def attachReplicatedResource(self, args):
+        rdUUID = args[0]
+        device = args[1]
+        res = self.s.attachReplicatedResource(rdUUID, device)
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        return 0, ''
+
+    def connectReplicatedResource(self, args):
+        rdUUID = args[0]
+        target = args[1]
+        res = self.s.connectReplicatedResource(rdUUID, target)
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        return 0, ''
+
+    def activateReplicatedResource(self, args):
+        rdUUID = args[0]
+        if len(args) == 2:
+            force = args[1]
+        else:
+            force = 'False'
+        res = self.s.activateReplicatedResource(rdUUID, force)
+        if res['status']['code']:
+            return res['status']['code'], res['status']['message']
+        return 0, ''
+
 if __name__ == '__main__':
     if _glusterEnabled:
         serv = ge.GlusterService()
@@ -2392,6 +2442,32 @@
                                  'Finish live replication to the destination '
                                  'domain'
                                  )),
+        'createReplicatedDevice': (
+            serv.createReplicatedDevice, (
+                '<device>', 'Creates new replicated device'
+            )),
+        'getReplicatedResourcesList': (
+            serv.getReplicatedResourcesList, (
+                '', 'Get replicated resources list'
+            )),
+        'getReplicatedResourceInfo': (
+            serv.getReplicatedResourceInfo, (
+                '<rdUUID>', 'Get replicated device info.'
+            )),
+        'attachReplicatedResource': (
+            serv.attachReplicatedResource, (
+                '<rdUUID> <device>',
+                'Attach a replicated resource to a block device.'
+            )),
+        'connectReplicatedResource': (
+            serv.connectReplicatedResource, (
+                '<rdUUID> <target>',
+                'Connects a replicated resource to a remote peer'
+            )),
+        'activateReplicatedResource': (
+            serv.activateReplicatedResource, (
+                '<rdUUID> [<force>]', 'Activates a replicated resource'
+            )),
     }
     if _glusterEnabled:
         commands.update(ge.getGlusterCmdDict(serv))
diff --git a/configure.ac b/configure.ac
index 6baa950..9553cc5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -147,6 +147,8 @@
 AC_PATH_PROG([DD_PATH], [dd], [/bin/dd])
 AC_PATH_PROG([DMIDECODE_PATH], [dmidecode], [/usr/sbin/dmidecode])
 AC_PATH_PROG([DMSETUP_PATH], [dmsetup], [/sbin/dmsetup])
+AC_PATH_PROG([DRBDMETA_PATH], [drbdmeta], [/sbin/drbdmeta])
+AC_PATH_PROG([DRBDSETUP_PATH], [drbdsetup], [/sbin/drbdsetup])
 AC_PATH_PROG([ECHO_PATH], [echo], [/bin/echo])
 AC_PATH_PROG([FSCK_PATH], [fsck], [/sbin/fsck])
 AC_PATH_PROG([FENCE_AGENT_PATH], [fence_ilo], [/usr/sbin/fence_ilo])
diff --git a/lib/vdsm/constants.py.in b/lib/vdsm/constants.py.in
index e7e2f83..e36de0b 100644
--- a/lib/vdsm/constants.py.in
+++ b/lib/vdsm/constants.py.in
@@ -91,6 +91,9 @@
 EXT_DMIDECODE = '@DMIDECODE_PATH@'
 EXT_DMSETUP = '@DMSETUP_PATH@'
 
+EXT_DRBDMETA = '@DRBDMETA_PATH@'
+EXT_DRBDSETUP = '@DRBDSETUP_PATH@'
+
 EXT_EDITNETWORK = '@VDSMDIR@/editNetwork'
 
 EXT_FENCE_PREFIX = os.path.dirname('@FENCE_AGENT_PATH@') + '/fence_'
diff --git a/vdsm.spec.in b/vdsm.spec.in
index dbb9d04..0711007 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -750,6 +750,7 @@
 %{_datadir}/%{vdsm_name}/storage/devicemapper.py*
 %{_datadir}/%{vdsm_name}/storage/dispatcher.py*
 %{_datadir}/%{vdsm_name}/storage/domainMonitor.py*
+%{_datadir}/%{vdsm_name}/storage/drbd.py*
 %{_datadir}/%{vdsm_name}/storage/fileSD.py*
 %{_datadir}/%{vdsm_name}/storage/fileUtils.py*
 %{_datadir}/%{vdsm_name}/storage/fileVolume.py*
diff --git a/vdsm/storage/Makefile.am b/vdsm/storage/Makefile.am
index ab3c387..0478add 100644
--- a/vdsm/storage/Makefile.am
+++ b/vdsm/storage/Makefile.am
@@ -29,6 +29,7 @@
 	devicemapper.py \
 	dispatcher.py \
 	domainMonitor.py \
+	drbd.py \
 	fileSD.py \
 	fileUtils.py \
 	fileVolume.py \
diff --git a/vdsm/storage/drbd.py b/vdsm/storage/drbd.py
new file mode 100644
index 0000000..3bbc954
--- /dev/null
+++ b/vdsm/storage/drbd.py
@@ -0,0 +1,324 @@
+#
+# Copyright 2009-2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import random
+import socket
+
+import utils
+import constants
+import threading
+import storage_exception as se
+
+DRBD_VERSION = "v08"
+DRBD_MAXUUID = 256 ** 8
+DRBD_MAXMINOR = 255
+DRBD_DEVPREFIX = "drbd"
+DRBD_BASEPORT = 7800
+
+KNOWN_VALUES = (
+    "Configured",
+    "Unconfigured",
+    "NA",
+)
+
+CONN_STATE_VALUES = (
+    "StandAlone",
+    "Disconnecting",
+    "Unconnected",
+    "Timeout",
+    "BrokenPipe",
+    "NetworkFailure",
+    "ProtocolError",
+    "WFConnection",
+    "WFReportParams",
+    "TearDown",
+    "Connected",
+    "StartingSyncS",
+    "StartingSyncT",
+    "WFBitMapS",
+    "WFBitMapT",
+    "WFSyncUUID",
+    "SyncSource",
+    "SyncTarget",
+    "PausedSyncS",
+    "PausedSyncT",
+    "VerifyS",
+    "VerifyT",
+    "Ahead",
+    "Behind",
+)
+
+ROLE_STATE_VALUES = (
+    "Primary",
+    "Secondary",
+    "Unknown",
+)
+
+DISK_STATE_VALUES = (
+    "Diskless",
+    "Attaching",
+    "Failed",
+    "Negotiating",
+    "Inconsistent",
+    "Outdated",
+    "DUnknown",
+    "Consistent",
+    "UpToDate",
+)
+
+
+class ReplicatedDevice(object):
+    @classmethod
+    def newUUID(cls):
+        return "%016X" % (random.randint(0, DRBD_MAXUUID),)
+
+    @classmethod
+    def readUUID(cls, device):
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDMETA, "0", DRBD_VERSION, device,
+            "internal", "read-dev-uuid"
+        ])
+
+        if rc != 0 or len(out) != 1:
+            raise se.ReplicatedDeviceError()
+
+        return out[0]
+
+    @classmethod
+    def writeUUID(cls, device, uuid):
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDMETA, "0", DRBD_VERSION, device,
+            "internal", "write-dev-uuid", uuid
+        ])
+
+        if rc != 0:
+            raise se.ReplicatedDeviceError()
+
+    @classmethod
+    def create(cls, device):
+        # Checking if the device was already initialized
+        try:
+            uuid = cls.readUUID(device)
+            raise se.ReplicatedDeviceInitialized(uuid)
+        except se.ReplicatedDeviceError:
+            pass
+
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDMETA, "0", DRBD_VERSION, device,
+            "internal", "create-md", "--force"
+        ])
+
+        if rc != 0:
+            raise se.ReplicatedDeviceError()
+
+        uuid = cls.newUUID()
+        cls.writeUUID(device, uuid)
+
+        if uuid != cls.readUUID(device):
+            raise se.ReplicatedDeviceError()
+
+        return uuid
+
+
+class ReplicatedStatus(dict):
+    # format:
+    #   "inkey"         ("outkey", default, "_decodeMethod", methodArgs...),
+    _statusMap = {
+        "_minor":       ("minor", None, "_decodeMinor"),
+        "_res_name":    ("resName", "", "_decodeValue", str),
+        "_volume":      ("volume", 0, "_decodeValue", int),
+        "_known":       ("known", "NA", "_decodeEnum", KNOWN_VALUES),
+        "_cstate":      ("connState",
+                         "Unconnected", "_decodeEnum", CONN_STATE_VALUES),
+        "_role":        ("roleState",
+                         "Unknown", "_decodeEnum", ROLE_STATE_VALUES),
+        "_peer":        ("peerState",
+                         "Unknown", "_decodeEnum", ROLE_STATE_VALUES),
+        "_disk":        ("diskState",
+                         "DUnknown", "_decodeEnum", DISK_STATE_VALUES),
+        "_pdisk":       ("peerDiskState",
+                         "DUnknown", "_decodeEnum", DISK_STATE_VALUES),
+        # This is a drbd bug, the same key is called in two different ways
+        # depending on the state of the resource. Remove me in the future.
+        "_pdsk":        ("peerDiskState",
+                         "DUnknown", "_decodeEnum", DISK_STATE_VALUES),
+        "_flags_susp":  ("flagsSusp", False, "_decodeFlags"),
+        "_flags_aftr_isp": ("flagsAfterIsp", False, "_decodeFlags"),
+        "_flags_peer_isp": ("flagsPeerIsp", False, "_decodeFlags"),
+        "_flags_user_isp": ("flagsUserIsp", False, "_decodeFlags"),
+        "_resynced_percent": ("resyncedPercent", 0, "_decodeValue", float),
+    }
+
+    def __init__(self, *args, **kwargs):
+        dict.__init__(self, *args, **kwargs)
+
+        for key, description in self._statusMap.items():
+            dict.__setitem__(self, description[0], description[1])
+
+    def __setitem__(self, item, value):
+        if item not in self._statusMap:
+            raise KeyError(item)
+
+        description = self._statusMap[item]
+
+        # Validating key value
+        validate = getattr(self, description[2])
+        value = validate(value, description[1], *description[3:])
+
+        dict.__setitem__(self, description[0], value)
+
+    def _decodeMinor(self, value, default):
+        value = int(value)
+        return value if value != 4294967295 else default
+
+    def _decodeValue(self, value, default, newtype):
+        return default if value == "" else newtype(value)
+
+    def _decodeEnum(self, value, default, enums):
+        if value in enums:
+            return value
+        elif default in enums:
+            return default
+        raise ValueError(default)
+
+    def _decodeFlags(self, value, default):
+        return True if value == "1" else default
+
+
+class ReplicatedResource(object):
+    minorLock = threading.Lock()
+
+    def __init__(self, rdUUID):
+        self.rdUUID = rdUUID
+
+    @classmethod
+    def attach(cls, rdUUID, device):
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDSETUP, "new-resource", rdUUID
+        ])
+
+        if rc != 0:
+            raise se.ReplicatedResourceError()
+
+        with cls.minorLock:
+            minor = str(cls._getFreeMinor())
+
+            rc, out, err = utils.execCmd([
+                constants.EXT_DRBDSETUP, "new-minor", rdUUID,
+                minor, "0"
+            ])
+
+            if rc != 0:
+                raise se.ReplicatedResourceError()
+
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDMETA, minor, DRBD_VERSION, device,
+            "internal", "apply-al"
+        ])
+
+        if rc != 0:
+            raise se.ReplicatedResourceError()
+
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDSETUP, "attach", minor, device,
+            device, "internal"
+        ])
+
+        if rc != 0:
+            raise se.ReplicatedResourceError()
+
+    @property
+    def status(self):
+        return ReplicatedResource.info(self.rdUUID)
+
+    @classmethod
+    def _getFreeMinor(cls):
+        usedminors = set(map(lambda x: x['minor'], cls.info()))
+
+        for minor in xrange(1, DRBD_MAXMINOR):
+            if minor not in usedminors:
+                return minor
+
+        raise se.ReplicatedResourceError()
+
+    @classmethod
+    def info(cls, resource=None):
+        target = resource if resource else "all"
+
+        rc, out, err = utils.execCmd([
+            constants.EXT_DRBDSETUP, "sh-status", target
+        ])
+
+        if rc != 20:
+            raise se.ReplicatedResourceError()
+
+        result = []
+        status = ReplicatedStatus()
+
+        for line in filter(lambda x: len(x) > 0, out):
+            if line == "_sh_status_process":
+                result.append(status)
+                status = ReplicatedStatus()
+                continue
+
+            key, value = line.split("=", 1)
+            status[key] = value
+
+        if resource:
+            if len(result) == 1:
+                return result[0]
+            else:
+                raise se.ReplicatedResourceError()
+
+        return result
+
+    # XXX: Using the force flag might lead to data corruption! It should be
+    #      used only during the device initialization or in an unrecoverable
+    #      split-brain situation.
+    def primary(self, force=False):
+        primary_minor = str(self.status['minor'])
+        primary_force = ["--force"] if force is True else []
+
+        rc, out, err = utils.execCmd([constants.EXT_DRBDSETUP, "primary",
+                                      primary_minor] + primary_force)
+        if rc != 0:
+            raise se.ReplicatedResourceError()
+
+    def connect(self, remote):
+        drbdport = DRBD_BASEPORT + self.status['minor']
+        remoteip = socket.gethostbyname(remote)
+
+        connect_opts = [
+            "ipv4:0.0.0.0:%d" % (drbdport,),
+            "ipv4:%s:%d" % (remoteip, drbdport),
+            "--protocol=C",
+            "--allow-two-primaries=yes",
+        ]
+
+        rc, out, err = utils.execCmd([constants.EXT_DRBDSETUP, "connect",
+                                      self.rdUUID] + connect_opts)
+        if rc != 0:
+            raise se.ReplicatedResourceError()
+
+
+def getReplicatedDevices():
+    for status in ReplicatedResource.info():
+        if status['minor'] and status['roleState'] == "Primary":
+            yield DRBD_DEVPREFIX + str(status['minor'])
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index ae35b11..eb342a2 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -45,6 +45,7 @@
 import glusterSD
 import localFsSD
 import lvm
+import drbd
 import fileUtils
 import multipath
 from sdc import sdCache
@@ -1969,17 +1970,23 @@
         vars.task.setDefaultException(
             se.VolumeGroupCreateError(str(vgname), str(devlist)))
         misc.validateUUID(vgname, 'vgname')
-        # getSharedLock(connectionsResource...)
-        knowndevs = set(multipath.getMPDevNamesIter())
+        #getSharedLock(connectionsResource...)
+        knownmpath = list(multipath.getMPDevNamesIter())
+        knowndrbd = list(drbd.getReplicatedDevices())
         size = 0
         devices = []
 
         for dev in devlist:
-            if dev in knowndevs:
-                devices.append(dev)
-                size += multipath.getDeviceSize(devicemapper.getDmId(dev))
+            # Finding the device in the known ones
+            if dev in knownmpath:
+                devname = devicemapper.getDmId(dev)
+            elif dev in knowndrbd:
+                devname = dev
             else:
                 raise se.InvalidPhysDev(dev)
+
+            devices.append(dev)
+            size += multipath.getDeviceSize(devname)
 
         # Minimal size check
         if size < MINIMALVGSIZE:
@@ -3417,3 +3424,80 @@
                 result[d] = repo_stats[d]['result']
 
         return result
+
+    @public
+    def createReplicatedDevice(self, device):
+        """
+        Creates a new replicated device (drbd).
+
+        :param device: The block device to be used.
+        :type device: str
+
+        :returns: The new device uuid.
+        :rtype: str
+        """
+        newUUID = drbd.ReplicatedDevice.create(device)
+        return dict(uuid=newUUID)
+
+    @public
+    def getReplicatedResourcesList(self):
+        """
+        List all the replicated resources in the system (drbd).
+
+        :returns: The replicated resources list.
+        :rtype: list
+        """
+        resources = drbd.ReplicatedResource.info()
+        return dict(resList=map(lambda x: x['resName'], resources))
+
+    @public
+    def getReplicatedResourceInfo(self, rdUUID):
+        """
+        Gets the info of a replicated resource (drbd).
+
+        :param rdUUID: The resource UUID.
+        :type rdUUID: UUID
+
+        :returns: The replicated resources information.
+        :rtype: dict
+        """
+        resource = dict(drbd.ReplicatedResource.info(rdUUID))
+        return dict(resInfo=resource)
+
+    @public
+    def attachReplicatedResource(self, rdUUID, device):
+        """
+        Attaches a replicated resource (drbd) to a block device.
+
+        :param rdUUID: The resource UUID.
+        :type rdUUID: UUID
+        :param device: The block device to be used.
+        :type device: str
+        """
+        drbd.ReplicatedResource.attach(rdUUID, device)
+
+    @public
+    def connectReplicatedResource(self, rdUUID, target):
+        """
+        Connects a replicated resource (drbd) to a remote peer.
+
+        :param rdUUID: The resource UUID.
+        :type rdUUID: UUID
+        :param target: The peer target address.
+        :type device: str
+        """
+        rd = drbd.ReplicatedResource(rdUUID)
+        rd.connect(target)
+
+    @public
+    def activateReplicatedResource(self, rdUUID, force=False):
+        """
+        Connects a replicated resource (drbd) to a remote peer.
+
+        :param rdUUID: The resource UUID.
+        :type rdUUID: UUID
+        :param target: The peer target address.
+        :type device: str
+        """
+        rd = drbd.ReplicatedResource(rdUUID)
+        rd.primary(misc.parseBool(force))
diff --git a/vdsm/storage/lvm.py b/vdsm/storage/lvm.py
index 97fe38a..351fca4 100644
--- a/vdsm/storage/lvm.py
+++ b/vdsm/storage/lvm.py
@@ -40,6 +40,7 @@
 from vdsm import constants
 import misc
 import multipath
+import drbd
 import storage_exception as se
 from vdsm.config import config
 import devicemapper
@@ -83,9 +84,8 @@
 LVM_FLAGS = ("--noheadings", "--units", "b", "--nosuffix", "--separator",
              SEPARATOR)
 
-PV_PREFIX = "/dev/mapper"
-# Assuming there are no spaces in the PV name
-re_pvName = re.compile(PV_PREFIX + '[^\s\"]+', re.MULTILINE)
+DEVICE_PREFIX = "/dev"
+MAPPER_PREFIX = "/dev/mapper"
 
 # operations lock
 LVM_OP_INVALIDATE = "lvm invalidate operation"
@@ -263,7 +263,12 @@
             if not self._filterStale:
                 return self._extraCfg
 
-            self._extraCfg = _buildConfig(multipath.getMPDevNamesIter())
+            devList = (
+                list(multipath.getMPDevNamesIter()) +
+                list(drbd.getReplicatedDevices())
+            )
+
+            self._extraCfg = _buildConfig(devList)
             _updateLvmConf(self._extraCfg)
             self._filterStale = False
 
@@ -635,8 +640,11 @@
 
 
 def _fqpvname(pv):
-    if pv and not pv.startswith(PV_PREFIX):
-        pv = os.path.join(PV_PREFIX, pv)
+    if pv and not pv.startswith(DEVICE_PREFIX):
+        if pv.startswith(drbd.DRBD_DEVPREFIX):
+            pv = os.path.join(DEVICE_PREFIX, pv)
+        else:
+            pv = os.path.join(MAPPER_PREFIX, pv)
     return pv
 
 
@@ -795,7 +803,10 @@
     Receives guids iterable.
     Returns (un)pvables, (un)succeed guids.
     """
-    devs = tuple("%s/%s" % (PV_PREFIX, dev) for dev in devices)
+    # FIXME: these new MAPPER_PREFIX entries should be handled to include
+    # drbd too, see the function _fqpvname.
+    devs = tuple("%s/%s" % (MAPPER_PREFIX, dev) for dev in devices)
+    re_pvName = re.compile(MAPPER_PREFIX + '[^\s\"]+', re.MULTILINE)
 
     options = ("--test",)
     rc, out, err = _createpv(devs, metadataSize, options)
diff --git a/vdsm/storage/storage_exception.py b/vdsm/storage/storage_exception.py
index c2c3dc8..d0a946e 100644
--- a/vdsm/storage/storage_exception.py
+++ b/vdsm/storage/storage_exception.py
@@ -1721,3 +1721,17 @@
     code = 855
     message = ("Could not acquire resource. "
                "Probably resource factory threw an exception.")
+
+
+#################################################
+#  Replicated Device Exceptions
+#################################################
+
+class ReplicatedDeviceError(StorageException):
+    code = 900
+    message = "Replicated device general error"
+
+
+class ReplicatedResourceError(StorageException):
+    code = 901
+    message = "Replicated resource general error"
diff --git a/vdsm/sudoers.vdsm.in b/vdsm/sudoers.vdsm.in
index 24031ec..c673688 100644
--- a/vdsm/sudoers.vdsm.in
+++ b/vdsm/sudoers.vdsm.in
@@ -24,6 +24,8 @@
     @SERVICE_PATH@ multipathd reload, \
     @ISCSIADM_PATH@ *, \
     @LVM_PATH@, \
+    @DRBDMETA_PATH@, \
+    @DRBDSETUP_PATH@, \
     @CAT_PATH@ /sys/block/*/device/../../*, \
     @CAT_PATH@ /sys/devices/platform/host*, \
     @CAT_PATH@ /etc/iscsi/iscsid.conf, \


--
To view, visit http://gerrit.ovirt.org/13585
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I33bb867ba6c7cfca54d31334554cb37db11aeeea
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce at redhat.com>


More information about the vdsm-patches mailing list