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