Adam Litke has uploaded a new change for review.
Change subject: storage: Factor out getAllVolumes
......................................................................
storage: Factor out getAllVolumes
The SDM garbage collector needs to a mapping of volumes by imageID.
Factor out this logic from getAllVolumes so it can be reused later.
Change-Id: If8c55edf6416dddc4a4f30b91422b3e968df2b99
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/fileSD.py
1 file changed, 17 insertions(+), 12 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/77/40377/1
diff --git a/vdsm/storage/fileSD.py b/vdsm/storage/fileSD.py
index 1220939..042f836 100644
--- a/vdsm/storage/fileSD.py
+++ b/vdsm/storage/fileSD.py
@@ -18,7 +18,6 @@
# Refer to the README and COPYING files for full details of the license
#
-import collections
import os
import errno
import logging
@@ -405,6 +404,21 @@
"""
pass
+ def getImageToVolumesMap(self):
+ volMetaPattern = os.path.join(self.mountpoint, self.sdUUID,
+ sd.DOMAIN_IMAGES, "*", "*.meta")
+ volMetaPaths = self.oop.glob.glob(volMetaPattern)
+ images = {}
+ for metaPath in volMetaPaths:
+ head, tail = os.path.split(metaPath)
+ volUUID, volExt = os.path.splitext(tail)
+ imgUUID = os.path.basename(head)
+ try:
+ images[imgUUID].append(volUUID)
+ except KeyError:
+ images[imgUUID] = [volUUID]
+ return images
+
def getAllVolumes(self):
"""
Return dict {volUUID: ((imgUUIDs,), parentUUID)} of the domain.
@@ -422,17 +436,8 @@
Template volumes have no parent, and thus we report BLANK_UUID as their
parentUUID.
"""
- volMetaPattern = os.path.join(self.mountpoint, self.sdUUID,
- sd.DOMAIN_IMAGES, "*", "*.meta")
- volMetaPaths = self.oop.glob.glob(volMetaPattern)
-
- # First create mapping from images to volumes
- images = collections.defaultdict(list)
- for metaPath in volMetaPaths:
- head, tail = os.path.split(metaPath)
- volUUID, volExt = os.path.splitext(tail)
- imgUUID = os.path.basename(head)
- images[imgUUID].append(volUUID)
+ # First get the mapping from images to volumes
+ images = self.getImageToVolumesMap()
# Using images to volumes mapping, we can create volumes to images
# mapping, detecting template volumes and template images, based on
--
To view, visit https://gerrit.ovirt.org/40377
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If8c55edf6416dddc4a4f30b91422b3e968df2b99
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: XXX: Insert sleep when creating block SD
......................................................................
XXX: Insert sleep when creating block SD
Change-Id: I10ed63d747f1353da824af8ec56ac8a6f66d666b
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockSD.py
1 file changed, 4 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/53/43553/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 0b8bdc7..0d5e403 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -896,6 +896,10 @@
# Create VMS file system
_createVMSfs(os.path.join("/dev", vgName, MASTERLV))
+ # XXX: When running an iSCSI server and initiator on the same host we
+ # need to wait a bit for IO to settle before deactivating LVs
+ import time
+ time.sleep(10)
lvm.deactivateLVs(vgName, MASTERLV)
path = lvm.lvPath(vgName, sd.METADATA)
--
To view, visit https://gerrit.ovirt.org/43553
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I10ed63d747f1353da824af8ec56ac8a6f66d666b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: sdm: Add decorators for sdm-only functions and their callers
......................................................................
sdm: Add decorators for sdm-only functions and their callers
Change-Id: Iaf736144e5640519851dc9175b5f17539d0ce23e
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/Makefile.am
A tests/sdm_tests.py
M vdsm.spec.in
M vdsm/storage/Makefile.am
A vdsm/storage/sdm.py
5 files changed, 102 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/56/43556/1
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f116fc4..5907a0d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -92,6 +92,7 @@
scheduleTests.py \
schemaTests.py \
schemaValidationTest.py \
+ sdm_tests.py \
securableTests.py \
sourceroutingTests.py \
sslhelper.py \
diff --git a/tests/sdm_tests.py b/tests/sdm_tests.py
new file mode 100644
index 0000000..95ae126
--- /dev/null
+++ b/tests/sdm_tests.py
@@ -0,0 +1,43 @@
+#
+# Copyright 2015 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
+#
+
+from testlib import VdsmTestCase
+
+from storage import sdm
+from storage.threadLocal import vars
+
+
+class RequireSDMTests(VdsmTestCase):
+ def setUp(self):
+ try:
+ delattr(vars, '__sdm__')
+ except AttributeError:
+ pass
+
+ @sdm.sdm_verb
+ def test_allowed(self):
+ self.assertTrue(self.sdm_fn())
+
+ def test_denied(self):
+ self.assertRaises(sdm.SDMFunctionNotCallable, self.sdm_fn)
+
+ @sdm.require_sdm
+ def sdm_fn(self):
+ return True
\ No newline at end of file
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 57e673e..24e0ab7 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -936,6 +936,7 @@
%{_datadir}/%{vdsm_name}/storage/clusterlock.py*
%{_datadir}/%{vdsm_name}/storage/sdc.py*
%{_datadir}/%{vdsm_name}/storage/sd.py*
+%{_datadir}/%{vdsm_name}/storage/sdm.py*
%{_datadir}/%{vdsm_name}/storage/securable.py*
%{_datadir}/%{vdsm_name}/storage/sp.py*
%{_datadir}/%{vdsm_name}/storage/spbackends.py*
diff --git a/vdsm/storage/Makefile.am b/vdsm/storage/Makefile.am
index e460518..51768ce 100644
--- a/vdsm/storage/Makefile.am
+++ b/vdsm/storage/Makefile.am
@@ -59,6 +59,7 @@
resourceManager.py \
sdc.py \
sd.py \
+ sdm.py \
securable.py \
sp.py \
spbackends.py \
diff --git a/vdsm/storage/sdm.py b/vdsm/storage/sdm.py
new file mode 100644
index 0000000..97e599f
--- /dev/null
+++ b/vdsm/storage/sdm.py
@@ -0,0 +1,56 @@
+#
+# Copyright 2015 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
+#
+
+from functools import wraps
+from storage.threadLocal import vars
+
+
+class SDMFunctionNotCallable(Exception):
+ pass
+
+
+def require_sdm(f):
+ """
+ SDM method decorator.
+
+ This decorator is used to mark methods that can only be called when the
+ storage is operating in SDM mode (ie. without SPM).
+ """
+ @wraps(f)
+ def wrapper(*args, **kwds):
+ if getattr(vars, '__sdm__', False):
+ return f(*args, **kwds)
+ else:
+ raise SDMFunctionNotCallable(f.__name__)
+ return wrapper
+
+
+def sdm_verb(f):
+ """
+ SDM verb decorator
+
+ This decorator indicates that a function is designed to work without SPM
+ and is approved to access SDM-only functions.
+ """
+ @wraps(f)
+ def wrapper(*args, **kwds):
+ vars.__sdm__ = True
+ return f(*args, **kwds)
+ return wrapper
--
To view, visit https://gerrit.ovirt.org/43556
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaf736144e5640519851dc9175b5f17539d0ce23e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: sdm: Add find_domain_manifest helpers
......................................................................
sdm: Add find_domain_manifest helpers
Change-Id: Ia5d139bde2349c8231141fe842d9ada96fa279fe
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M tests/Makefile.am
A tests/domainmanifestfactory_tests.py
M tests/manifest_tests.py
M tests/storagefakelib.py
M tests/storagetestutils.py
M vdsm.spec.in
M vdsm/storage/Makefile.am
M vdsm/storage/blockSD.py
A vdsm/storage/domainManifestFactory.py
M vdsm/storage/glusterSD.py
M vdsm/storage/localFsSD.py
M vdsm/storage/nfsSD.py
12 files changed, 214 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/55/43555/1
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9cc3692..f116fc4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -43,6 +43,7 @@
cpuProfileTests.py \
deviceTests.py \
domainDescriptorTests.py \
+ domainmanifestfactory_tests.py \
encodingTests.py \
executorTests.py \
fileSDTests.py \
diff --git a/tests/domainmanifestfactory_tests.py b/tests/domainmanifestfactory_tests.py
new file mode 100644
index 0000000..4c3f63e
--- /dev/null
+++ b/tests/domainmanifestfactory_tests.py
@@ -0,0 +1,124 @@
+# Copyright 2015 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 os
+import uuid
+
+from testlib import VdsmTestCase, namedTemporaryDir
+from monkeypatch import MonkeyPatchScope
+from storagefakelib import FakeLVM
+from storagetestutils import make_blocksd_manifest, make_vg, \
+ make_filesd_manifest
+
+from storage import sd, blockSD, fileSD, localFsSD, mount
+from storage import storage_exception as se
+from storage import domainManifestFactory
+
+
+class DomainManifestFactoryTests(VdsmTestCase):
+ def get_patches(self, tmpdir, lvm):
+ return [(blockSD, 'lvm', lvm),
+ (blockSD, 'selectMetadata', lambda x: {}),
+ (sd.StorageDomain, 'storage_repository', tmpdir),
+ (mount, 'isMounted', lambda x: True)]
+
+ def make_mnt(self, tmpdir, link_name):
+ mntdir = os.path.join(tmpdir, sd.DOMAIN_MNT_POINT)
+ os.mkdir(mntdir)
+ os.symlink(tmpdir, os.path.join(mntdir, link_name))
+
+ def test_localfs_layout(self):
+ with namedTemporaryDir() as tmpdir:
+ self.make_mnt(tmpdir, '_localfssd')
+ lvm = FakeLVM(tmpdir)
+ with MonkeyPatchScope(self.get_patches(tmpdir, lvm)):
+ manifest = make_filesd_manifest(tmpdir)
+ found_manifest = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ self.assertEquals(manifest.sdUUID, found_manifest.sdUUID)
+ self.assertIsInstance(found_manifest,
+ fileSD.FileStorageDomainManifest)
+
+ def test_nfs_layout(self):
+ with namedTemporaryDir() as tmpdir:
+ self.make_mnt(tmpdir, '192.168.1.1:_localfssd')
+ lvm = FakeLVM(tmpdir)
+ with MonkeyPatchScope(self.get_patches(tmpdir, lvm)):
+ manifest = make_filesd_manifest(tmpdir)
+ found_manifest = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ self.assertEquals(manifest.sdUUID, found_manifest.sdUUID)
+ self.assertIsInstance(found_manifest,
+ fileSD.FileStorageDomainManifest)
+
+ def test_glusterfs_layout(self):
+ with namedTemporaryDir() as tmpdir:
+ mntdir = os.path.join(tmpdir, sd.DOMAIN_MNT_POINT)
+ glusterdir = os.path.join(mntdir, sd.GLUSTERSD_DIR)
+ os.makedirs(glusterdir)
+ os.symlink(tmpdir, os.path.join(glusterdir, 'host:_glustersd'))
+
+ lvm = FakeLVM(tmpdir)
+ with MonkeyPatchScope(self.get_patches(tmpdir, lvm)):
+ manifest = make_filesd_manifest(tmpdir)
+ found_manifest = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ self.assertEquals(manifest.sdUUID, found_manifest.sdUUID)
+ self.assertEquals(manifest.sdUUID, found_manifest.sdUUID)
+ self.assertIsInstance(found_manifest,
+ fileSD.FileStorageDomainManifest)
+
+ def test_block_layout(self):
+ with namedTemporaryDir() as tmpdir:
+ lvm = FakeLVM(tmpdir)
+ with MonkeyPatchScope(self.get_patches(tmpdir, lvm)):
+ manifest = make_blocksd_manifest()
+ vg_name = make_vg(lvm, manifest)
+ lvm.vgmd[vg_name]['tags'] = [blockSD.STORAGE_DOMAIN_TAG]
+ found_manifest = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ self.assertEquals(manifest.sdUUID, found_manifest.sdUUID)
+ self.assertIsInstance(found_manifest,
+ blockSD.BlockStorageDomainManifest)
+
+ def test_cached_finder(self):
+ def _trap(unused):
+ raise RuntimeError()
+
+ with namedTemporaryDir() as tmpdir:
+ self.make_mnt(tmpdir, '_localfssd')
+ lvm = FakeLVM(tmpdir)
+ patches = self.get_patches(tmpdir, lvm)
+ with MonkeyPatchScope(patches):
+ manifest = make_filesd_manifest(tmpdir)
+ res1 = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ patches.append((localFsSD, 'findDomainManifest', _trap))
+ with MonkeyPatchScope(patches):
+ res2 = domainManifestFactory.produce(
+ manifest.sdUUID, manifest._metadata)
+ self.assertEquals(res1.sdUUID, res2.sdUUID)
+
+ def test_not_found(self):
+ sdUUID = str(uuid.uuid4())
+ with namedTemporaryDir() as tmpdir:
+ lvm = FakeLVM(tmpdir)
+ with MonkeyPatchScope(self.get_patches(tmpdir, lvm)):
+ self.assertRaises(se.StorageDomainDoesNotExist,
+ domainManifestFactory.produce, sdUUID)
\ No newline at end of file
diff --git a/tests/manifest_tests.py b/tests/manifest_tests.py
index a22d7cf..967b663 100644
--- a/tests/manifest_tests.py
+++ b/tests/manifest_tests.py
@@ -161,7 +161,6 @@
imguuid = str(uuid.uuid4())
imagepath = manifest.getImagePath(imguuid)
- os.makedirs(os.path.dirname(imagepath))
with open(imagepath, 'w') as f:
f.truncate(0)
self.assertEquals(set(), manifest.getAllImages())
diff --git a/tests/storagefakelib.py b/tests/storagefakelib.py
index cb40fbb..bf79d91 100644
--- a/tests/storagefakelib.py
+++ b/tests/storagefakelib.py
@@ -23,6 +23,7 @@
from copy import deepcopy
from storage import lvm as real_lvm
+from storage import storage_exception as se
class FakeLVM(object):
@@ -154,7 +155,11 @@
return real_lvm.PV(**md)
def getVG(self, vgName):
- vg_md = deepcopy(self.vgmd[vgName])
+ try:
+ vg_md = deepcopy(self.vgmd[vgName])
+ except KeyError:
+ raise se.VolumeGroupDoesNotExist(vgName)
+
vg_attr = real_lvm.VG_ATTR(**vg_md['attr'])
vg_md['attr'] = vg_attr
return real_lvm.VG(**vg_md)
diff --git a/tests/storagetestutils.py b/tests/storagetestutils.py
index ed052af..eae803a 100644
--- a/tests/storagetestutils.py
+++ b/tests/storagetestutils.py
@@ -79,7 +79,7 @@
if metadata is None:
metadata = {sd.DMDK_VERSION: 3}
manifest = fileSD.FileStorageDomainManifest(domain_path, metadata)
- os.makedirs(os.path.join(manifest.domaindir, sduuid, sd.DOMAIN_IMAGES))
+ os.makedirs(os.path.join(manifest.domaindir, sd.DOMAIN_IMAGES))
return manifest
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 4ba9812..57e673e 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -906,6 +906,7 @@
%{_datadir}/%{vdsm_name}/storage/curlImgWrap.py*
%{_datadir}/%{vdsm_name}/storage/devicemapper.py*
%{_datadir}/%{vdsm_name}/storage/dispatcher.py*
+%{_datadir}/%{vdsm_name}/storage/domainManifestFactory.py
%{_datadir}/%{vdsm_name}/storage/monitor.py*
%{_datadir}/%{vdsm_name}/storage/fileSD.py*
%{_datadir}/%{vdsm_name}/storage/fileUtils.py*
diff --git a/vdsm/storage/Makefile.am b/vdsm/storage/Makefile.am
index a4ec93a..e460518 100644
--- a/vdsm/storage/Makefile.am
+++ b/vdsm/storage/Makefile.am
@@ -31,6 +31,7 @@
curlImgWrap.py \
devicemapper.py \
dispatcher.py \
+ domainManifestFactory.py \
fileSD.py \
fileUtils.py \
fileVolume.py \
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 121cc6b..6de2737 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -1426,5 +1426,10 @@
return BlockStorageDomain(BlockStorageDomain.findDomainPath(sdUUID))
+def findDomainManifest(sdUUID, metadata=None):
+ return BlockStorageDomainManifest(
+ BlockStorageDomain.findDomainPath(sdUUID), metadata)
+
+
def getStorageDomainsList():
return [vg.name for vg in lvm.getAllVGs() if _isSD(vg)]
diff --git a/vdsm/storage/domainManifestFactory.py b/vdsm/storage/domainManifestFactory.py
new file mode 100644
index 0000000..fced9de
--- /dev/null
+++ b/vdsm/storage/domainManifestFactory.py
@@ -0,0 +1,60 @@
+#
+# Copyright 2015 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 logging
+
+import blockSD, glusterSD, localFsSD, nfsSD
+import storage_exception as se
+
+
+log = logging.getLogger('Storage.domainManifestFactory')
+
+domain_manifest_producers = {}
+
+
+def produce(sdUUID, metadata=None):
+ log.error("looking for domain manifest %s", sdUUID)
+
+ # Check our cache of finder functions first. Since a domain manifest
+ # cannot change its type we don't have to worry about invalidation.
+ try:
+ producer = domain_manifest_producers[sdUUID]
+ except KeyError:
+ pass
+ else:
+ return producer(sdUUID, metadata)
+
+ # The order is somewhat important, it's ordered
+ # by how quickly get can find the domain. For instance
+ # if an nfs mount is unavailable we will get stuck
+ # until it times out, this should affect fetching
+ # of block\local domains. If for any case in the future
+ # this changes, please update the order.
+ for mod in (blockSD, glusterSD, localFsSD, nfsSD):
+ try:
+ manifest = mod.findDomainManifest(sdUUID, metadata)
+ domain_manifest_producers[sdUUID] = mod.findDomainManifest
+ return manifest
+ except se.StorageDomainDoesNotExist:
+ pass
+ except Exception:
+ log.exception("Error while looking for domain `%s`", sdUUID)
+
+ raise se.StorageDomainDoesNotExist(sdUUID)
diff --git a/vdsm/storage/glusterSD.py b/vdsm/storage/glusterSD.py
index 2931083..a62e242 100644
--- a/vdsm/storage/glusterSD.py
+++ b/vdsm/storage/glusterSD.py
@@ -30,3 +30,8 @@
def findDomain(sdUUID):
return GlusterStorageDomain(GlusterStorageDomain.findDomainPath(sdUUID))
+
+
+def findDomainManifest(sdUUID, metadata=None):
+ return fileSD.FileStorageDomainManifest(
+ GlusterStorageDomain.findDomainPath(sdUUID), metadata)
diff --git a/vdsm/storage/localFsSD.py b/vdsm/storage/localFsSD.py
index 7e11330..b4e0ce0 100644
--- a/vdsm/storage/localFsSD.py
+++ b/vdsm/storage/localFsSD.py
@@ -119,3 +119,8 @@
def findDomain(sdUUID):
return LocalFsStorageDomain(LocalFsStorageDomain.findDomainPath(sdUUID))
+
+
+def findDomainManifest(sdUUID, metadata=None):
+ return fileSD.FileStorageDomainManifest(
+ LocalFsStorageDomain.findDomainPath(sdUUID), metadata)
\ No newline at end of file
diff --git a/vdsm/storage/nfsSD.py b/vdsm/storage/nfsSD.py
index 1f94439..739efc8 100644
--- a/vdsm/storage/nfsSD.py
+++ b/vdsm/storage/nfsSD.py
@@ -120,3 +120,8 @@
def findDomain(sdUUID):
return NfsStorageDomain(NfsStorageDomain.findDomainPath(sdUUID))
+
+
+def findDomainManifest(sdUUID, metadata=None):
+ return fileSD.FileStorageDomainManifest(
+ NfsStorageDomain.findDomainPath(sdUUID), metadata)
--
To view, visit https://gerrit.ovirt.org/43555
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia5d139bde2349c8231141fe842d9ada96fa279fe
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: storage: Factor apparentsize adjustment into a reusable function
......................................................................
storage: Factor apparentsize adjustment into a reusable function
When creating a new volume sometimes the actual size is larger than the
requested size due to underlying storage limitations (such as physical
extent granularity in LVM). In these cases, the new volume's size must
be adjusted to match the actual size. The SDM volume creation code
would also like to use this function so extract it into the
VolumeMetadata class.
Change-Id: I7395850e127b941fc50ae8d5659868a2499b5076
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/volume.py
1 file changed, 28 insertions(+), 18 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/44/44044/1
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index f7e5bc0..723b3d9 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -495,6 +495,31 @@
puuid)
return None
+ @classmethod
+ def adjust_new_volume_size(cls, dom_manifest, img_id, vol_id, req_size,
+ vol_format):
+ # When the volume format is raw what the guest sees is the apparent
+ # size of the file/device therefore if the requested size doesn't
+ # match the apparent size (eg: physical extent granularity in LVM)
+ # we need to update the size value so that the metadata reflects
+ # the correct state.
+ if vol_format == RAW_FORMAT:
+ apparentSize = int(dom_manifest.getVSize(img_id, vol_id) /
+ BLOCK_SIZE)
+ if apparentSize < req_size:
+ cls.log.error("The volume %s apparent size %s is smaller "
+ "than the requested size %s",
+ vol_id, apparentSize, req_size)
+ raise se.VolumeCreationError()
+ if apparentSize > req_size:
+ cls.log.info("The requested size for volume %s doesn't "
+ "match the granularity on domain %s, "
+ "updating the volume size from %s to %s",
+ vol_id, dom_manifest.sdUUID, req_size,
+ apparentSize)
+ return apparentSize
+ return req_size
+
class Volume(object):
log = logging.getLogger('Storage.Volume')
@@ -850,24 +875,9 @@
cls.log.error("Failed to create volume %s: %s", volPath, e)
vars.task.popRecovery()
raise
- # When the volume format is raw what the guest sees is the apparent
- # size of the file/device therefore if the requested size doesn't
- # match the apparent size (eg: physical extent granularity in LVM)
- # we need to update the size value so that the metadata reflects
- # the correct state.
- if volFormat == RAW_FORMAT:
- apparentSize = int(dom.getVSize(imgUUID, volUUID) / BLOCK_SIZE)
- if apparentSize < size:
- cls.log.error("The volume %s apparent size %s is smaller "
- "than the requested size %s",
- volUUID, apparentSize, size)
- raise se.VolumeCreationError()
- if apparentSize > size:
- cls.log.info("The requested size for volume %s doesn't "
- "match the granularity on domain %s, "
- "updating the volume size from %s to %s",
- volUUID, sdUUID, size, apparentSize)
- size = apparentSize
+
+ size = VolumeMetadata.adjust_new_volume_size(dom, imgUUID, volUUID,
+ size, volFormat)
vars.task.pushRecovery(
task.Recovery("Create volume metadata rollback", clsModule,
--
To view, visit https://gerrit.ovirt.org/44044
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7395850e127b941fc50ae8d5659868a2499b5076
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: storage: Rename _share to share_to_image
......................................................................
storage: Rename _share to share_to_image
When a new volume is created whose parent is a template volume, that
template must be "shared" into the new volume's image since volume
chains only link volumes in the same image. This logic is reusable by
the SDM create volume flow but _share should be renamed to
share_to_image to remove the _ which designates this as a protected
method.
Change-Id: I44c7fe43ada38aa97bbd9c08438a0ee686680330
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockVolume.py
M vdsm/storage/fileVolume.py
M vdsm/storage/volume.py
3 files changed, 3 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/46/44046/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index 47336b9..23e636e 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -314,7 +314,7 @@
def refreshVolume(self):
lvm.refreshLVs(self.sdUUID, (self.volUUID,))
- def _share(self, dstImgPath):
+ def share_to_image(self, dstImgPath):
"""
Share this volume to dstImgPath
"""
diff --git a/vdsm/storage/fileVolume.py b/vdsm/storage/fileVolume.py
index 15ca05b..c5b8667 100644
--- a/vdsm/storage/fileVolume.py
+++ b/vdsm/storage/fileVolume.py
@@ -300,7 +300,7 @@
os.path.join(dstImgPath, self.volUUID))
self.oop.utils.forceLink(self._getLeaseVolumePath(), dstLeasePath)
- def _share(self, dstImgPath):
+ def share_to_image(self, dstImgPath):
"""
Share this volume to dstImgPath, including the metadata and the lease
"""
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index 0d61643..951efe0 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -598,7 +598,7 @@
self.md.removeMetadata()
def _share(self, dstImgPath):
- return self.md._share(dstImgPath)
+ return self.md.share_to_image(dstImgPath)
@classmethod
def _getModuleAndClass(cls):
--
To view, visit https://gerrit.ovirt.org/44046
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I44c7fe43ada38aa97bbd9c08438a0ee686680330
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: ImageManifest: move getChain
......................................................................
ImageManifest: move getChain
The implementation of getChain instantiates storagedomain and volume
objects. This must be fixed. We must fix all callers of getChain to
work with VolumeMetadata objects instead of Volume objects.
Change-Id: Iffd24be3ba74ccdea8dfc744b579c0cf63771cdb
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/image.py
1 file changed, 71 insertions(+), 66 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/49/44049/1
diff --git a/vdsm/storage/image.py b/vdsm/storage/image.py
index bd79f6e..f852f3c 100644
--- a/vdsm/storage/image.py
+++ b/vdsm/storage/image.py
@@ -89,6 +89,8 @@
class ImageManifest(object):
+ log = logging.getLogger('Storage.ImageManifest')
+
def __init__(self, repoPath):
self.repoPath = repoPath
@@ -105,6 +107,74 @@
log.info("Create placeholder %s for image's volumes", img_dir)
os.mkdir(img_dir)
return img_dir
+
+ def getChain(self, sdUUID, imgUUID, volUUID=None):
+ """
+ Return the chain of volumes of image as a sorted list
+ (not including a shared base (template) if any)
+ """
+ chain = []
+ volclass = sdCache.produce(sdUUID).getVolumeClass()
+
+ # Use volUUID when provided
+ if volUUID:
+ srcVol = volclass(self.repoPath, sdUUID, imgUUID, volUUID)
+
+ # For template images include only one volume (the template itself)
+ # NOTE: this relies on the fact that in a template there is only
+ # one volume
+ if srcVol.isShared():
+ return [srcVol]
+
+ # Find all the volumes when volUUID is not provided
+ else:
+ # Find all volumes of image
+ uuidlist = volclass.getImageVolumes(self.repoPath, sdUUID, imgUUID)
+
+ if not uuidlist:
+ raise se.ImageDoesNotExistInSD(imgUUID, sdUUID)
+
+ srcVol = volclass(self.repoPath, sdUUID, imgUUID, uuidlist[0])
+
+ # For template images include only one volume (the template itself)
+ if len(uuidlist) == 1 and srcVol.isShared():
+ return [srcVol]
+
+ # Searching for the leaf
+ for vol in uuidlist:
+ srcVol = volclass(self.repoPath, sdUUID, imgUUID, vol)
+
+ if srcVol.isLeaf():
+ break
+
+ srcVol = None
+
+ if not srcVol:
+ self.log.error("There is no leaf in the image %s", imgUUID)
+ raise se.ImageIsNotLegalChain(imgUUID)
+
+ # We have seen corrupted chains that cause endless loops here.
+ # https://bugzilla.redhat.com/1125197
+ seen = set()
+
+ # Build up the sorted parent -> child chain
+ while not srcVol.isShared():
+ chain.insert(0, srcVol)
+ seen.add(srcVol.volUUID)
+
+ parentUUID = srcVol.getParentId()
+ if parentUUID == volume.BLANK_UUID:
+ break
+
+ if parentUUID in seen:
+ self.log.error("Image %s volume %s has invalid parent UUID %s",
+ imgUUID, srcVol.volUUID, parentUUID)
+ raise se.ImageIsNotLegalChain(imgUUID)
+
+ srcVol = srcVol.produceParent()
+
+ self.log.info("sdUUID=%s imgUUID=%s chain=%s ", sdUUID, imgUUID, chain)
+ return chain
class Image:
@@ -179,72 +249,7 @@
return newsize
def getChain(self, sdUUID, imgUUID, volUUID=None):
- """
- Return the chain of volumes of image as a sorted list
- (not including a shared base (template) if any)
- """
- chain = []
- volclass = sdCache.produce(sdUUID).getVolumeClass()
-
- # Use volUUID when provided
- if volUUID:
- srcVol = volclass(self.repoPath, sdUUID, imgUUID, volUUID)
-
- # For template images include only one volume (the template itself)
- # NOTE: this relies on the fact that in a template there is only
- # one volume
- if srcVol.isShared():
- return [srcVol]
-
- # Find all the volumes when volUUID is not provided
- else:
- # Find all volumes of image
- uuidlist = volclass.getImageVolumes(self.repoPath, sdUUID, imgUUID)
-
- if not uuidlist:
- raise se.ImageDoesNotExistInSD(imgUUID, sdUUID)
-
- srcVol = volclass(self.repoPath, sdUUID, imgUUID, uuidlist[0])
-
- # For template images include only one volume (the template itself)
- if len(uuidlist) == 1 and srcVol.isShared():
- return [srcVol]
-
- # Searching for the leaf
- for vol in uuidlist:
- srcVol = volclass(self.repoPath, sdUUID, imgUUID, vol)
-
- if srcVol.isLeaf():
- break
-
- srcVol = None
-
- if not srcVol:
- self.log.error("There is no leaf in the image %s", imgUUID)
- raise se.ImageIsNotLegalChain(imgUUID)
-
- # We have seen corrupted chains that cause endless loops here.
- # https://bugzilla.redhat.com/1125197
- seen = set()
-
- # Build up the sorted parent -> child chain
- while not srcVol.isShared():
- chain.insert(0, srcVol)
- seen.add(srcVol.volUUID)
-
- parentUUID = srcVol.getParentId()
- if parentUUID == volume.BLANK_UUID:
- break
-
- if parentUUID in seen:
- self.log.error("Image %s volume %s has invalid parent UUID %s",
- imgUUID, srcVol.volUUID, parentUUID)
- raise se.ImageIsNotLegalChain(imgUUID)
-
- srcVol = srcVol.produceParent()
-
- self.log.info("sdUUID=%s imgUUID=%s chain=%s ", sdUUID, imgUUID, chain)
- return chain
+ return self.manifest.getChain(sdUUID, imgUUID, volUUID)
def getTemplate(self, sdUUID, imgUUID):
"""
--
To view, visit https://gerrit.ovirt.org/44049
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Iffd24be3ba74ccdea8dfc744b579c0cf63771cdb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: storage: block: getChildren: Do not count uninit LVs as children
......................................................................
storage: block: getChildren: Do not count uninit LVs as children
Any LV with the tag TAG_VOL_UNINIT is not a real volume yet. It is
either in the process of being created or deleted. It should not appear
in the children list of its parent until the tag is removed.
Change-Id: I03e489df8478de26b01ce34f41e87aecc04512ed
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockVolume.py
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/71/44571/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index ee531f3..51f60ea 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -183,7 +183,8 @@
"""
lvs = lvm.lvsByTag(self.sdUUID,
"%s%s" % (TAG_PREFIX_PARENT, self.volUUID))
- return tuple(lv.name for lv in lvs)
+
+ return tuple(lv.name for lv in lvs if TAG_VOL_UNINIT not in lv.tags)
def getImage(self):
"""
--
To view, visit https://gerrit.ovirt.org/44571
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I03e489df8478de26b01ce34f41e87aecc04512ed
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Adam Litke has uploaded a new change for review.
Change subject: Garbage volumes are not part of an image
......................................................................
Garbage volumes are not part of an image
Change-Id: I8776a4b48cc8d16f420426fb28d4696b6f2bf357
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockVolume.py
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/30/44830/1
diff --git a/vdsm/storage/blockVolume.py b/vdsm/storage/blockVolume.py
index 9baa3d2..af11725 100644
--- a/vdsm/storage/blockVolume.py
+++ b/vdsm/storage/blockVolume.py
@@ -334,7 +334,7 @@
(template)
"""
lvs = lvm.lvsByTag(sdUUID, "%s%s" % (TAG_PREFIX_IMAGE, imgUUID))
- return [lv.name for lv in lvs]
+ return [lv.name for lv in lvs if TAG_VOL_GARBAGE not in lv.tags]
@logskip("ResourceManager")
def llPrepare(self, rw=False, setrw=False):
--
To view, visit https://gerrit.ovirt.org/44830
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8776a4b48cc8d16f420426fb28d4696b6f2bf357
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: vm: Cleaner vm stats thread initialization
......................................................................
vm: Cleaner vm stats thread initialization
The vm stats thread was initialized too late, leading to unneeded checks
and unclear try except blocks when trying to stop the thread.
This patch changes AdvancedStatsThread so it keeps a thread instance
instead of inheriting from Thread, and initialize it in Vm.__init__, so
it is always available when we access it.
Change-Id: I2917de42b76ee3dc8b27bdc23b33f3c984a7cc68
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/virt/sampling.py
M vdsm/virt/vm.py
2 files changed, 11 insertions(+), 18 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/99/39299/1
diff --git a/vdsm/virt/sampling.py b/vdsm/virt/sampling.py
index 3206b97..848bb36 100644
--- a/vdsm/virt/sampling.py
+++ b/vdsm/virt/sampling.py
@@ -401,7 +401,7 @@
return self._samples.last()
-class AdvancedStatsThread(threading.Thread):
+class AdvancedStatsThread(object):
"""
A thread that runs the registered AdvancedStatsFunction objects
for statistic and monitoring purpose.
@@ -412,9 +412,8 @@
"""
Initialize an AdvancedStatsThread object
"""
- threading.Thread.__init__(self)
self.daemon = daemon
-
+ self._thread = None
self._log = log
self._stopEvent = threading.Event()
self._contEvent = threading.Event()
@@ -426,7 +425,7 @@
"""
Register the functions listed as arguments
"""
- if self.isAlive():
+ if self._thread is not None:
raise RuntimeError("AdvancedStatsThread is started")
for statsFunction in args:
@@ -437,7 +436,9 @@
Start the execution of the thread and exit
"""
self._log.debug("Start statistics collection")
- threading.Thread.start(self)
+ self._thread = threading.Thread(target=self._run)
+ self._thread.daemon = self.daemon
+ self._thread.start()
def stop(self):
"""
@@ -464,7 +465,7 @@
def getLastSampleTime(self):
return self._statsTime
- def run(self):
+ def _run(self):
self._log.debug("Stats thread started")
self._contEvent.set()
diff --git a/vdsm/virt/vm.py b/vdsm/virt/vm.py
index 28054bf..1bc04e7 100644
--- a/vdsm/virt/vm.py
+++ b/vdsm/virt/vm.py
@@ -779,7 +779,7 @@
self._initTimeRTC = long(self.conf.get('timeOffset', 0))
self._guestEvent = vmstatus.POWERING_UP
self._guestEventTime = 0
- self._vmStats = None
+ self._vmStats = VmStatsThread(self)
self._guestCpuRunning = False
self._guestCpuLock = threading.Lock()
self._startTime = time.time() - \
@@ -1269,7 +1269,7 @@
return
toSave = self.status()
toSave['startTime'] = self._startTime
- if self.lastStatus != vmstatus.DOWN and self._vmStats:
+ if self.lastStatus != vmstatus.DOWN:
guestInfo = self.guestAgent.getGuestInfo()
toSave['username'] = guestInfo['username']
toSave['guestIPs'] = guestInfo['guestIPs']
@@ -1758,7 +1758,7 @@
decStats = {}
try:
- if self._vmStats and self._vmStats.getLastSampleTime() is not None:
+ if self._vmStats.getLastSampleTime() is not None:
decStats = self._vmStats.get()
self._setUnresponsiveIfTimeout(
stats,
@@ -2001,19 +2001,11 @@
return domxml.toxml()
def startVmStats(self):
- self._vmStats = VmStatsThread(self)
self._vmStats.start()
self._guestEventTime = self._startTime
def stopVmStats(self):
- # this is less clean that it could be, but we can get here from
- # many flows and with various locks held
- # (_releaseLock, _shutdownLock)
- # _vmStats may be None already, and we're good with that.
- try:
- self._vmStats.stop()
- except AttributeError:
- pass
+ self._vmStats.stop()
@staticmethod
def _guestSockCleanup(sock):
--
To view, visit https://gerrit.ovirt.org/39299
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2917de42b76ee3dc8b27bdc23b33f3c984a7cc68
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Piotr Kliczewski has uploaded a new change for review.
Change subject: xmlrpc: retry when flushing socket
......................................................................
xmlrpc: retry when flushing socket
m2crypto requires retry of write and we need to make sure that we do it once
flushing data before closing a socket. In order to do so we need to move
original implementation to our code base.
Bug-Url: https://bugzilla.redhat.com/1261255
Change-Id: I52dd6ad304a82ff6c8d3dff12a38269684abf055
Signed-off-by: pkliczewski <piotr.kliczewski(a)gmail.com>
---
M vdsm/rpc/bindingxmlrpc.py
1 file changed, 19 insertions(+), 1 deletion(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/37/47637/2
diff --git a/vdsm/rpc/bindingxmlrpc.py b/vdsm/rpc/bindingxmlrpc.py
index c521cd8..9f77457 100644
--- a/vdsm/rpc/bindingxmlrpc.py
+++ b/vdsm/rpc/bindingxmlrpc.py
@@ -25,6 +25,7 @@
import libvirt
import threading
import re
+import socket
import sys
from vdsm.password import (ProtectedPassword,
@@ -33,6 +34,7 @@
from vdsm import utils
from vdsm import xmlrpc
from vdsm.define import doneCode, errCode
+from vdsm.m2cutils import SSL
from vdsm.netinfo import getDeviceByIP
import API
from vdsm.exception import VdsmException
@@ -288,7 +290,23 @@
return r
def finish(self):
- xmlrpc.IPXMLRPCRequestHandler.finish(self)
+ if not self.wfile.closed:
+ while True:
+ try:
+ self.wfile.flush()
+ break
+ except socket.error:
+ # An final socket error may have occurred here,
+ # such as the local error ECONNABORTED.
+ break
+ except SSL.SSLError as e:
+ if e.message == 'bad write retry':
+ continue
+ else:
+ break
+
+ self.wfile.close()
+ self.rfile.close()
threadLocal.client = None
threadLocal.server = None
threadLocal.flowID = None
--
To view, visit https://gerrit.ovirt.org/47637
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I52dd6ad304a82ff6c8d3dff12a38269684abf055
Gerrit-PatchSet: 2
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Piotr Kliczewski <piotr.kliczewski(a)gmail.com>
Gerrit-Reviewer: automation(a)ovirt.org
Adam Litke has uploaded a new change for review.
Change subject: fix remove: iterate while del
......................................................................
fix remove: iterate while del
Change-Id: I594c98cf54ed93d045b76df1c6faa5122277b19e
Signed-off-by: Adam Litke <alitke(a)redhat.com>
---
M vdsm/storage/blockSD.py
1 file changed, 2 insertions(+), 2 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/72/44572/1
diff --git a/vdsm/storage/blockSD.py b/vdsm/storage/blockSD.py
index 74bf82d..832fb8b 100644
--- a/vdsm/storage/blockSD.py
+++ b/vdsm/storage/blockSD.py
@@ -201,8 +201,8 @@
vols = _getVolsTree(sdUUID)
# Remove volumes awaiting garbage collection from the result
- for vol_id in vols.iterkeys():
- if vols[vol_id].garbage_meta_id is not None:
+ for vol_id, vol_info in vols.items():
+ if vol_info.garbage_meta_id is not None:
del vols[vol_id]
res = {}
--
To view, visit https://gerrit.ovirt.org/44572
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I594c98cf54ed93d045b76df1c6faa5122277b19e
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke(a)redhat.com>