Change in vdsm[master]: Refactor metadata operations
alitke at redhat.com
alitke at redhat.com
Mon Jan 25 08:48:25 UTC 2016
Adam Litke has uploaded a new change for review.
Change subject: Refactor metadata operations
......................................................................
Refactor metadata operations
Volume metadata can be represented as a dictionary and as a string of
delineated key value pairs. Extract this logic out of the Volume
classes into a new VolumeMetadata class which can be unit tested. Once
refactored, this code can be reused by new SDM code as well.
Change-Id: I4fee56b30c13a3c1cede8489338ed60f4e1d5eab
Signed-off-by: Adam Litke <alitke at redhat.com>
---
A tests/volume_metadata_test.py
M vdsm/storage/volume.py
2 files changed, 165 insertions(+), 16 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/71/52671/1
diff --git a/tests/volume_metadata_test.py b/tests/volume_metadata_test.py
new file mode 100644
index 0000000..e5f716f
--- /dev/null
+++ b/tests/volume_metadata_test.py
@@ -0,0 +1,100 @@
+# Copyright 2016 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 time
+import uuid
+
+from testlib import VdsmTestCase
+
+from storage import image, sd, volume
+from vdsm import define
+
+
+def get_params(sd_id=None, img_id=None, parent_vol_id=None, size=None,
+ vol_format=None, prealloc=None, vol_type=None, disk_type=None,
+ description=None, legality=None):
+ return dict(
+ sd_id=sd_id or str(uuid.uuid4()),
+ img_id=img_id or str(uuid.uuid4()),
+ parent_vol_id=parent_vol_id or str(uuid.uuid4()),
+ size=size or 1024 * define.Mbytes,
+ vol_format=vol_format or volume.type2name(volume.RAW_FORMAT),
+ prealloc=prealloc or volume.type2name(volume.SPARSE_VOL),
+ vol_type=vol_type or volume.type2name(volume.LEAF_VOL),
+ disk_type=disk_type or str(image.SYSTEM_DISK_TYPE),
+ description=description or "",
+ legality=legality or volume.LEGAL_VOL
+ )
+
+
+class VolumeMetadataTests(VdsmTestCase):
+ params_to_fields = dict(
+ sd_id=volume.DOMAIN,
+ img_id=volume.IMAGE,
+ parent_vol_id=volume.PUUID,
+ size=volume.SIZE,
+ vol_format=volume.FORMAT,
+ prealloc=volume.TYPE,
+ vol_type=volume.VOLTYPE,
+ disk_type=volume.DISKTYPE,
+ description=volume.DESCRIPTION,
+ legality=volume.LEGALITY
+ )
+
+ def test_create(self):
+ params = get_params()
+ md = volume.VolumeMetadata(**params)
+ self._compare_params_to_info(params, md.info())
+
+ def test_format(self):
+ params = get_params()
+ md = volume.VolumeMetadata(**params)
+ format_str = md.format()
+ format_list = format_str.split('\n')
+ self.assertEqual(['EOF', ''], format_list[-2:])
+ format_list = format_list[:-2]
+
+ for param_name, info_field in self.params_to_fields.items():
+ line = "%s=%s" % (info_field, params[param_name])
+ self.assertIn(line, format_list)
+
+ # The following lines are constant
+ self.assertIn("%s=0" % volume.MTIME, format_list)
+ self.assertIn("%s=" % sd.DMDK_POOLS, format_list)
+
+ # CTIME is set dynamically so check .info for the correct value
+ ctime_line = "%s=%i" % (volume.CTIME, md.info()[volume.CTIME])
+ self.assertIn(ctime_line, format_list)
+
+ def test_long_description(self):
+ params = get_params(description="!" * volume.METADATA_SIZE)
+ md = volume.VolumeMetadata(**params)
+ self.assertEqual(volume.DESCRIPTION_SIZE, len(md.description))
+
+ def _compare_params_to_info(self, params, info):
+ for param_name, info_field in self.params_to_fields.items():
+ self.assertEqual(params[param_name], info[info_field])
+
+ # These fields are automatically filled in and have a constant value
+ self.assertEqual(0, info[volume.MTIME])
+ self.assertEqual("", info[sd.DMDK_POOLS])
+
+ # CTIME is filled in with the current time. We'll just test that it
+ # is close to now.
+ self.assertLess(time.time() - info[volume.CTIME], 10)
diff --git a/vdsm/storage/volume.py b/vdsm/storage/volume.py
index c26f236..cf2a8f1 100644
--- a/vdsm/storage/volume.py
+++ b/vdsm/storage/volume.py
@@ -165,6 +165,68 @@
TYPE_NETWORK = "network"
+class VolumeMetadata(object):
+ log = logging.getLogger('Storage.VolumeMetadata')
+
+ def __init__(self, sd_id, img_id, parent_vol_id, size, vol_format,
+ prealloc, vol_type, disk_type, description="",
+ legality=ILLEGAL_VOL):
+ self.sd_id = str(sd_id)
+ self.img_id = str(img_id)
+ self.parent_vol_id = str(parent_vol_id)
+ self.size = int(size)
+ self.vol_format = str(vol_format)
+ self.prealloc = str(prealloc)
+ self.vol_type = str(vol_type)
+ self.disk_type = str(disk_type)
+ self.description = description
+ self.legality = str(legality)
+ self.ctime = int(time.time())
+ self.mtime = 0
+
+ @property
+ def description(self):
+ return self._description
+
+ @description.setter
+ def description(self, desc):
+ self._description = VolumeManifest.validateDescription(desc)
+
+ def format(self):
+ """
+ Format metadata string in storage format.
+
+ Raises MetadataOverflowError if formatted metadata is too long.
+ """
+ lines = ["%s=%s\n" % (key.strip(), str(value).strip())
+ for key, value in self.info().iteritems()]
+ lines.append("EOF\n")
+ data = "".join(lines)
+ if len(data) > METADATA_SIZE:
+ raise se.MetadataOverflowError(data)
+ return data
+
+ def info(self):
+ """
+ Return metadata in dictionary format
+ """
+ return {
+ FORMAT: str(self.vol_format),
+ TYPE: str(self.prealloc),
+ VOLTYPE: str(self.vol_type),
+ DISKTYPE: str(self.disk_type),
+ SIZE: int(self.size),
+ CTIME: int(self.ctime),
+ sd.DMDK_POOLS: "", # obsolete
+ DOMAIN: str(self.sd_id),
+ IMAGE: str(self.img_id),
+ DESCRIPTION: str(self.description),
+ PUUID: str(self.parent_vol_id),
+ MTIME: int(self.mtime),
+ LEGALITY: str(self.legality),
+ }
+
+
class VolumeManifest(object):
log = logging.getLogger('Storage.VolumeManifest')
@@ -524,22 +586,9 @@
@classmethod
def newMetadata(cls, metaId, sdUUID, imgUUID, puuid, size, format, type,
voltype, disktype, desc="", legality=ILLEGAL_VOL):
- meta = {
- FORMAT: str(format),
- TYPE: str(type),
- VOLTYPE: str(voltype),
- DISKTYPE: str(disktype),
- SIZE: int(size),
- CTIME: int(time.time()),
- sd.DMDK_POOLS: "", # obsolete
- DOMAIN: str(sdUUID),
- IMAGE: str(imgUUID),
- DESCRIPTION: cls.validateDescription(desc),
- PUUID: str(puuid),
- MTIME: 0,
- LEGALITY: str(legality),
- }
- cls.createMetadata(metaId, meta)
+ meta = VolumeMetadata(sdUUID, imgUUID, puuid, size, format, type,
+ voltype, disktype, desc, legality)
+ cls.createMetadata(metaId, meta.info())
return meta
def refreshVolume(self):
--
To view, visit https://gerrit.ovirt.org/52671
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4fee56b30c13a3c1cede8489338ed60f4e1d5eab
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke at redhat.com>
More information about the vdsm-patches
mailing list