From ff5c11c0952771ce1ae85078a347dc471da68ba1 Mon Sep 17 00:00:00 2001 From: mcreach Date: Fri, 12 Jul 2024 16:28:01 +0200 Subject: [PATCH] Fix growvols multipath partition_delimiter detect On nodes with Fiber Channel multipath, the growvols command is failing sometimes with the following stack trace: Traceback (most recent call last): File "/usr/local/sbin/growvols", line 650, in sys.exit(main(sys.argv)) File "/usr/local/sbin/growvols", line 541, in main partnum = find_next_partnum(devices, disk) File "/usr/local/sbin/growvols", line 341, in find_next_partnum max_partnum = max(max_partnum, int(dev_name[disk_name_length:])) ValueError: invalid literal for int() with base 10: 'p1' The error is related to the kernel naming scheme for disk partitions. If the disk name is ending with a digit, the kernel adds "pX" (where X is the partition number) instead of just "X" when the disk name ends with a letter. Consulting the manual page multipath.conf(5), the partition_delimiter is configurable. If partition_delimiter is (the default) a delimiter 'p' is inserted only if the map name ends in a digit. If however the user configured a partition_delimiter, it will always be used. To try to handle both cases, use a regular expression to catch only the digits at the end of the string. Authored-By: mcr.opensource@gmail.com Co-Authored-By: hjensas@redhat.com Closes-Bug: #2109988 Change-Id: Ifbd58000601b7fc5635dcc2c7a897462000319b0 --- .../growvols/static/usr/local/sbin/growvols | 13 ++++++++++++- .../elements/growvols/tests/test_growvols.py | 14 ++++++++++++++ ...ipath-partition-delimiter-b93d07653b635a7c.yaml | 8 ++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/fix-growvols-multipath-partition-delimiter-b93d07653b635a7c.yaml diff --git a/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols b/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols index 91b4235fc..591b5342f 100755 --- a/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols +++ b/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols @@ -43,6 +43,9 @@ UNIT_BYTES_FORMAT = { 'GiB': 1073741824 } +# Regular expression to get digits at the end of a string +DIGITS_EOF_STR_RE = re.compile(r'\d+$') + # Only create growth partition if there is at least 1GiB available MIN_DISK_SPACE_BYTES = UNIT_BYTES['GiB'] @@ -363,7 +366,15 @@ def find_next_partnum(devices, disk): if dev_name in seen_devs: continue seen_devs.add(dev_name) - max_partnum = max(max_partnum, int(dev_name[disk_name_length:])) + # Multipath device names may have a partition_delimiter between + # the base device name and the partition number. By default, if + # partition_delimiter is unset in the multipath configuration and + # the base name ends in a digit, a 'p' is inserted. + # A regular expression is used to reliably extract trailing + # digits, regardless the presence of a partition delimiter or not. + max_partnum = max(max_partnum, + int(DIGITS_EOF_STR_RE.search( + dev_name[disk_name_length:]).group(0))) return max_partnum + 1 diff --git a/diskimage_builder/elements/growvols/tests/test_growvols.py b/diskimage_builder/elements/growvols/tests/test_growvols.py index 5676de69d..5af8e537a 100644 --- a/diskimage_builder/elements/growvols/tests/test_growvols.py +++ b/diskimage_builder/elements/growvols/tests/test_growvols.py @@ -11,6 +11,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +import copy import importlib import os import sys @@ -488,6 +489,19 @@ class TestGrowvols(base.BaseTestCase): disk = growvols.find_disk(opts, devices) self.assertEqual(6, growvols.find_next_partnum(devices, disk)) + def test_find_next_partnum_multipath_partition_delimiter(self): + opts = mock.Mock() + opts.device = 'mpath2' + local_lsblk = copy.deepcopy(LSBLK_MULTIPATH) + local_lsblk = local_lsblk.replace('mpatha1', 'mpath2p1') + local_lsblk = local_lsblk.replace('mpatha2', 'mpath2p2') + local_lsblk = local_lsblk.replace('mpatha3', 'mpath2p3') + local_lsblk = local_lsblk.replace('mpatha4', 'mpath2p4') + local_lsblk = local_lsblk.replace('mpatha', 'mpath2') + devices = list(growvols.parse_shell_vars(local_lsblk)) + disk = growvols.find_disk(opts, devices) + self.assertEqual(6, growvols.find_next_partnum(devices, disk)) + def test_find_next_device_name(self): devices = list(growvols.parse_shell_vars(LSBLK)) disk = { diff --git a/releasenotes/notes/fix-growvols-multipath-partition-delimiter-b93d07653b635a7c.yaml b/releasenotes/notes/fix-growvols-multipath-partition-delimiter-b93d07653b635a7c.yaml new file mode 100644 index 000000000..49b19b48c --- /dev/null +++ b/releasenotes/notes/fix-growvols-multipath-partition-delimiter-b93d07653b635a7c.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed an issue in the growvols element where a ``partition_delimiter`` + inserted between the device name and the partition number for multipath + devices was not handled correctly. This fix resolves `bug 2109988 + `_. +