Resolves: rhbz#1155151
We need our uuids obtained from mdadm to be the canonical format internally, as we need to compare them to other UUIDs obtained from other sources, which are in canonical form.
But the outside world needs to see mdadm's own format UUIDs.
Hence, we need a conversion function to convert from canonical UUIDs to mdadm format UUIDs.
There is an MDRaidArrayDevice property, mdadmFormatUUID, which invokes the conversion function. It returns None if the uuid is unconvertable.
This property is substituted for uuid wherever appropriate. If some checking was done for presence of UUID in these contexts, do appropriate checking for availability of formattedUUID. Where no checking was done previously, do not insert checking.
In one location, use context manager for writing to a file, for neatness, since the code has to be touched anyway.
Signed-off-by: mulhern amulhern@redhat.com --- blivet/devicelibs/mdraid.py | 29 +++++++++++++++++++++++++++++ blivet/devices.py | 33 +++++++++++++++++++++++++-------- tests/devicelibs_test/mdraid_test.py | 9 ++++++++- 3 files changed, 62 insertions(+), 9 deletions(-)
diff --git a/blivet/devicelibs/mdraid.py b/blivet/devicelibs/mdraid.py index f4ed875..e9a8bcb 100644 --- a/blivet/devicelibs/mdraid.py +++ b/blivet/devicelibs/mdraid.py @@ -22,6 +22,7 @@
import os import re +import string
from .. import util from ..errors import MDRaidError @@ -360,3 +361,31 @@ def name_from_md_node(node):
log.debug("returning %s", name) return name + +def mduuid_from_canonical(a_uuid): + """ Change a canonicalized uuid to mdadm's preferred format. + + :param str a_uuid: a string representing a UUID. + + :returns: a UUID in mdadm's preferred format + :rtype: str + + :raises MDRaidError: if it can not do the conversion + + mdadm's UUIDs are actual 128 bit uuids, but it formats them strangely. + This converts a uuid from canonical form to mdadm's form. + Example: + mdadm UUID: '3386ff85:f5012621:4a435f06:1eb47236' + canonical UUID: '3386ff85-f501-2621-4a43-5f061eb47236' + """ + NUM_DIGITS = 32 + a_uuid = a_uuid.replace('-', '') + + if len(a_uuid) != NUM_DIGITS: + raise MDRaidError("Missing digits in stripped UUID %s." % a_uuid) + + if any(c not in string.hexdigits for c in a_uuid): + raise MDRaidError("Non-hex digits in stripped UUID %s." % a_uuid) + + CHUNK_LEN = 8 + return ":".join(a_uuid[n:n+CHUNK_LEN] for n in range(0, NUM_DIGITS, CHUNK_LEN)) diff --git a/blivet/devices.py b/blivet/devices.py index 59a3879..43c918d 100644 --- a/blivet/devices.py +++ b/blivet/devices.py @@ -3826,11 +3826,11 @@ class MDRaidArrayDevice(ContainerDevice): self._size = self.currentSize self._type = "mdbiosraidarray"
- if self.exists and self.uuid and not flags.testing: + if self.exists and self.mdadmFormatUUID and not flags.testing: # this is a hack to work around mdadm's insistence on giving # really high minors to arrays it has no config entry for - open("/etc/mdadm.conf", "a").write("ARRAY %s UUID=%s\n" - % (self.path, self.uuid)) + with open("/etc/mdadm.conf", "a") as c: + c.write("ARRAY %s UUID=%s\n" % (self.path, self.mdadmFormatUUID))
def _verifyMemberFormat(self, member): if member.type == "mdcontainer": @@ -3839,6 +3839,23 @@ class MDRaidArrayDevice(ContainerDevice): return super(MDRaidArrayDevice, self)._verifyMemberFormat(member)
@property + def mdadmFormatUUID(self): + """ This array's UUID, formatted for external use. + + :returns: the array's UUID in mdadm format, if available + :rtype: str or NoneType + """ + formatted_uuid = None + + if self.uuid is not None: + try: + formatted_uuid = mdraid.mduuid_from_canonical(self.uuid) + except errors.MDRaidError: + pass + + return formatted_uuid + + @property def level(self): """ Return the raid level
@@ -3940,16 +3957,16 @@ class MDRaidArrayDevice(ContainerDevice): @property def mdadmConfEntry(self): """ This array's mdadm.conf entry. """ - if self.memberDevices is None or not self.uuid: + if self.memberDevices is None or not self.mdadmFormatUUID: raise errors.DeviceError("array is not fully defined", self.name)
# containers and the sets within must only have a UUID= parameter if self.type == "mdcontainer" or self.type == "mdbiosraidarray": fmt = "ARRAY %s UUID=%s\n" - return fmt % (self.path, self.uuid) + return fmt % (self.path, self.mdadmFormatUUID)
fmt = "ARRAY %s level=%s num-devices=%d UUID=%s\n" - return fmt % (self.path, self.level, self.memberDevices, self.uuid) + return fmt % (self.path, self.level, self.memberDevices, self.mdadmFormatUUID)
@property def totalDevices(self): @@ -4161,7 +4178,7 @@ class MDRaidArrayDevice(ContainerDevice):
mdraid.mdactivate(self.path, members=disks, - array_uuid=self.uuid) + array_uuid=self.mdadmFormatUUID)
def _postTeardown(self, recursive=False): super(MDRaidArrayDevice, self)._postTeardown(recursive=recursive) @@ -4286,7 +4303,7 @@ class MDRaidArrayDevice(ContainerDevice): return self.type == "mdbiosraidarray"
def dracutSetupArgs(self): - return set(["rd.md.uuid=%s" % self.uuid]) + return set(["rd.md.uuid=%s" % self.mdadmFormatUUID])
def populateKSData(self, data): if self.isDisk: diff --git a/tests/devicelibs_test/mdraid_test.py b/tests/devicelibs_test/mdraid_test.py index e6fdf55..11f5569 100755 --- a/tests/devicelibs_test/mdraid_test.py +++ b/tests/devicelibs_test/mdraid_test.py @@ -48,6 +48,13 @@ class MDRaidTestCase(unittest.TestCase): version="version"), mdraid.MD_SUPERBLOCK_SIZE)
+ def testMisc(self): + """ Miscellaneous testing. """ + self.assertEqual( + mdraid.mduuid_from_canonical('3386ff85-f501-2621-4a43-5f061eb47236'), + '3386ff85:f5012621:4a435f06:1eb47236' + ) + class MDRaidAsRootTestCase(loopbackedtestcase.LoopBackedTestCase):
def __init__(self, methodName='runTest', deviceSpec=None): @@ -184,7 +191,7 @@ class SimpleRaidTest(MDRaidAsRootTestCase): with self.assertRaises(MDRaidError): mdraid.mdactivate("/dev/md1")
- self.assertIsNone(mdraid.mdactivate(self._dev_name, array_uuid=info_pre['UUID'])) + self.assertIsNone(mdraid.mdactivate(self._dev_name, array_uuid=mdraid.mduuid_from_canonical(info_pre['UUID']))) time.sleep(2) info_post = mdraid.mddetail(self._dev_name)