curtin-dev team mailing list archive
-
curtin-dev team
-
Mailing list archive
-
Message #01344
Re: [Merge] ~mwhudson/curtin:lp-1893818 into curtin:master
Some more inline questions.
I definitely want to discuss the devtype mpath-partition, mpath-disk values. We cannot write out a curtin storage config with type:mpath-disk type:mpath-partition values; they aren't in the block schema.
Diff comments:
> diff --git a/curtin/block/multipath.py b/curtin/block/multipath.py
> index 7ad1791..ef67165 100644
> --- a/curtin/block/multipath.py
> +++ b/curtin/block/multipath.py
> @@ -81,18 +81,18 @@ def is_mpath_partition(devpath, info=None):
> if devpath.startswith('/dev/dm-'):
> if not info:
> info = udev.udevadm_info(devpath)
> - if 'DM_PART' in udev.udevadm_info(devpath):
> + if 'DM_PART' in info and 'DM_MPATH' in info:
Is it possible to have DM_PART and not have DM_MPATH?
> result = True
>
> LOG.debug("%s is multipath device partition? %s", devpath, result)
> return result
>
>
> -def mpath_partition_to_mpath_id(devpath):
> - """ Return the mpath id of a multipath partition. """
> +def mpath_partition_to_mpath_id_and_partnumber(devpath):
> + """ Return the mpath id and partition number of a multipath partition. """
> info = udev.udevadm_info(devpath)
> - if 'DM_MPATH' in info:
> - return info['DM_MPATH']
> + if 'DM_MPATH' in info and 'DM_PART' in info:
> + return info['DM_MPATH'], info['DM_PART']
Since this is for partitions, let's structure it like:
info = udev.udevadm_info(devpath)
if is_mpath_partition(devpath, info=info) # passing info saves an second exec
return info['DM_MPATH'], info['DM_PART']
return None, None
>
> return None
>
> diff --git a/curtin/storage_config.py b/curtin/storage_config.py
> index e6c33cc..dfe13a8 100644
> --- a/curtin/storage_config.py
> +++ b/curtin/storage_config.py
> @@ -453,72 +453,11 @@ class ProbertParser(object):
>
> return None
>
> - def is_mpath(self, blockdev):
> - if blockdev.get('DM_MULTIPATH_DEVICE_PATH') == "1":
> - return True
> + def is_mpath_disk(self, blockdev):
> + return blockdev.get('DM_UUID', '').startswith('mpath-')
Why change this? Do we see devices with DM_MULTIPATH_DEVICE_PATH but no MD_UUID?
>
> - return bool('mpath-' in blockdev.get('DM_UUID', ''))
> -
> - def get_mpath_name(self, blockdev):
> - mpath_data = self.probe_data.get('multipath')
> - if not mpath_data:
> - return None
> -
> - bd_name = blockdev['DEVNAME']
> - if blockdev['DEVTYPE'] == 'partition':
> - bd_name = self.partition_parent_devname(blockdev)
> - bd_name = os.path.basename(bd_name)
> - for path in mpath_data.get('paths', []):
> - if bd_name == path.get('device'):
> - rv = path.get('multipath')
> - return rv
> -
> - def find_mpath_member(self, blockdev):
> - if blockdev.get('DM_MULTIPATH_DEVICE_PATH') == "1":
> - # find all other DM_MULTIPATH_DEVICE_PATH devs with same serial
> - serial = blockdev.get('ID_SERIAL')
> - members = sorted([os.path.basename(dev['DEVNAME'])
> - for dev in self.blockdev_data.values()
> - if dev.get("ID_SERIAL", "") == serial and
> - dev['DEVTYPE'] == blockdev['DEVTYPE']])
> - # [/dev/sda, /dev/sdb]
> - # [/dev/sda1, /dev/sda2, /dev/sdb1, /dev/sdb2]
> -
> - else:
> - dm_mpath = blockdev.get('DM_MPATH')
> - dm_uuid = blockdev.get('DM_UUID')
> - dm_part = blockdev.get('DM_PART')
> - dm_name = blockdev.get('DM_NAME')
> -
> - if dm_mpath:
> - multipath = dm_mpath
> - elif dm_name:
> - multipath = dm_name
> - else:
> - # part1-mpath-30000000000000064
> - # mpath-30000000000000064
> - # mpath-36005076306ffd6b60000000000002406
> - match = re.search(r'mpath\-([a-zA-Z]*|\d*)+$', dm_uuid)
> - if not match:
> - LOG.debug('Failed to extract multipath ID pattern from '
> - 'DM_UUID value: "%s"', dm_uuid)
> - return None
> - # remove leading 'mpath-'
> - multipath = match.group(0)[6:]
> - mpath_data = self.probe_data.get('multipath')
> - if not mpath_data:
> - return None
> - members = sorted([path['device'] for path in mpath_data['paths']
> - if path['multipath'] == multipath])
> -
> - # append partition number if present
> - if dm_part:
> - members = [member + dm_part for member in members]
> -
> - if len(members):
> - return members[0]
> -
> - return None
> + def is_mpath_partition(self, blockdev):
> + return "DM_MPATH" in blockdev and "DM_PART" in blockdev
>
> def blockdev_to_id(self, blockdev):
> """ Examine a blockdev dictionary and return a tuple of curtin
> @@ -539,15 +478,13 @@ class ProbertParser(object):
> if 'DM_LV_NAME' in blockdev:
> devtype = 'lvm-partition'
> name = blockdev['DM_LV_NAME']
> - elif self.is_mpath(blockdev):
> - # extract a multipath member device
> - member = self.find_mpath_member(blockdev)
> - if member:
> - name = member
> - else:
> - name = blockdev['DM_UUID']
> - if 'DM_PART' in blockdev:
> - devtype = 'partition'
> + elif self.is_mpath_disk(blockdev):
> + devtype = 'mpath-disk'
> + name = blockdev['DM_NAME']
> + elif self.is_mpath_partition(blockdev):
> + devtype = 'mpath-partition'
I thought we had a discussion about exporting mpath-* as devtypes in storage config; we either need to add new types to the storage schema or replace these with 'disk' and 'partition'.
> + name = '{}-part{}'.format(
> + blockdev['DM_MPATH'], blockdev['DM_PART'])
> elif is_dmcrypt(blockdev):
> devtype = 'dmcrypt'
> name = blockdev['DM_NAME']
> @@ -681,10 +618,15 @@ class BlockdevParser(ProbertParser):
> errors = []
>
> for devname, data in self.blockdev_data.items():
> - # skip composed devices here, except partitions
> + # skip composed devices here, except partitions and multipath
> if data.get('DEVPATH', '').startswith('/devices/virtual/block'):
> - if data.get('DEVTYPE', '') != "partition":
> - continue
> + if not self.is_mpath_disk(data):
> + if not self.is_mpath_partition(data):
> + if data.get('DEVTYPE', '') != "partition":
> + continue
> + # skip disks that are members of multipath devices
> + if data.get('DM_MULTIPATH_DEVICE_PATH') == '1':
if is_mpath_disk(data)?
> + continue
> entry = self.asdict(data)
> if entry:
> try:
> @@ -698,7 +640,10 @@ class BlockdevParser(ProbertParser):
> def valid_id(self, id_value):
> # reject wwn=0x0+
> if id_value.lower().startswith('0x'):
> - return int(id_value, 16) > 0
> + try:
> + return int(id_value, 16) > 0
> + except ValueError:
> + return True
What case of id_value are we allowing through which is not hex?
> # accept non-empty (removing whitspace) strings
> return len(''.join(id_value.split())) > 0
>
> @@ -796,23 +751,35 @@ class BlockdevParser(ProbertParser):
>
> if entry['type'] == 'partition':
> attrs = blockdev_data['attrs']
> - entry['number'] = int(attrs['partition'])
> - parent_devname = self.partition_parent_devname(blockdev_data)
> - parent_blockdev = self.blockdev_data[parent_devname]
> - if 'ID_PART_TABLE_TYPE' not in parent_blockdev:
> - # Exclude the fake partition that the kernel creates
> - # for an otherwise unformatted FBA dasd.
> - dasds = self.probe_data.get('dasd', {})
> - dasd_config = dasds.get(parent_devname, {})
> - if dasd_config.get('type', 'ECKD') == 'FBA':
> - return None
> + if self.is_mpath_partition(blockdev_data):
> + entry['number'] = int(blockdev_data['DM_PART'])
> + parent_mpath = blockdev_data['DM_MPATH']
> + for data in self.blockdev_data.values():
> + if data.get('DM_NAME') == parent_mpath:
> + parent_blockdev = data
> + break
> + else:
> + raise ValueError("cannot find parent")
Including some additional context will make debugging storage_config parsing failures a bit easier:
raise ValueError("Cannot find parent mpath device %s for %s" % (parent_mpath, devname))
> + self_name = '/dev/mapper/{}-part{}'.format(
> + parent_mpath, entry['number'])
> + else:
> + entry['number'] = int(attrs['partition'])
> + self_name = blockdev_data['DEVNAME']
> + parent_devname = self.partition_parent_devname(blockdev_data)
> + parent_blockdev = self.blockdev_data[parent_devname]
> + if 'ID_PART_TABLE_TYPE' not in parent_blockdev:
> + # Exclude the fake partition that the kernel creates
> + # for an otherwise unformatted FBA dasd.
> + dasds = self.probe_data.get('dasd', {})
> + dasd_config = dasds.get(parent_devname, {})
> + if dasd_config.get('type', 'ECKD') == 'FBA':
> + return None
> ptable = parent_blockdev.get('partitiontable')
> if ptable:
> part = None
> for pentry in ptable['partitions']:
> node = pentry['node']
> - node_p = node.replace(parent_devname, '')
> - if node_p.replace('p', '') == attrs['partition']:
> + if node == self_name:
> part = pentry
> break
>
> @@ -880,6 +847,9 @@ class FilesystemParser(ProbertParser):
> errors.append(err)
> continue
>
> + if blockdev_data.get('DM_MULTIPATH_DEVICE_PATH') == "1":
is_mpath_disk()?
> + continue
> +
> # no floppy, no cdrom
> if blockdev_data['MAJOR'] in ["11", "2"]:
> continue
--
https://code.launchpad.net/~mwhudson/curtin/+git/curtin/+merge/392353
Your team curtin developers is subscribed to branch curtin:master.
References