diff --git a/os_xenapi/dom0/etc/xapi.d/plugins/partition_utils.py b/os_xenapi/dom0/etc/xapi.d/plugins/partition_utils.py index 9a1434b..dad572f 100644 --- a/os_xenapi/dom0/etc/xapi.d/plugins/partition_utils.py +++ b/os_xenapi/dom0/etc/xapi.d/plugins/partition_utils.py @@ -16,8 +16,10 @@ # NOTE: XenServer still only supports Python 2.4 in it's dom0 userspace # which means the Nova xenapi plugins must use only Python 2.4 features +from distutils.version import StrictVersion import logging import os +import re import time import dom0_pluginlib as pluginlib @@ -35,14 +37,39 @@ def wait_for_dev(session, dev_path, max_seconds): return "" +def _get_sfdisk_version(): + out = utils.run_command(['/sbin/sfdisk', '-v']) + if out: + # Return the first two numbers from the version. + # In XS6.5, it's 2.13-pre7. Just return 2.13 for this case. + pattern = re.compile("(\d+)\.(\d+)") + match = pattern.search(out.split('\n')[0]) + if match: + return match.group(0) + + def make_partition(session, dev, partition_start, partition_end): + # Since XS7.0 which has sfdisk V2.23, we observe sfdisk has a bug + # that sfdisk will wrongly calculate cylinders when specify Sector + # as unit (-uS). That bug will cause the partition operation failed. + # And that's fixed in 2.26. So as a workaround, let's use the option + # of '--force' for version <=2.25 and >=2.23. '--force' will ignore + # the wrong cylinder value but works as expected. + VER_FORCE_MIN = '2.23' + VER_FORCE_MAX = '2.25' dev_path = utils.make_dev_path(dev) if partition_end != "-": raise pluginlib.PluginError("Can only create unbounded partitions") - utils.run_command(['sfdisk', '-uS', dev_path], - '%s,;\n' % (partition_start)) + sfdisk_ver = _get_sfdisk_version() + cmd_list = ['sfdisk', '-uS', dev_path] + if sfdisk_ver: + if StrictVersion(sfdisk_ver) >= StrictVersion(VER_FORCE_MIN) and \ + StrictVersion(sfdisk_ver) <= StrictVersion(VER_FORCE_MAX): + cmd_list = ['sfdisk', '--force', '-uS', dev_path] + + utils.run_command(cmd_list, '%s,;\n' % (partition_start)) def _mkfs(fs, path, label): diff --git a/os_xenapi/tests/plugins/test_partition_utils.py b/os_xenapi/tests/plugins/test_partition_utils.py index d73d98b..1a1c059 100644 --- a/os_xenapi/tests/plugins/test_partition_utils.py +++ b/os_xenapi/tests/plugins/test_partition_utils.py @@ -100,10 +100,59 @@ class PartitionUtils(plugin_test.PluginTestBase): self.partition_utils._mkfs('swap', '/dev/sda1', 'ignored') mock_run.assert_called_with(['mkswap', '/dev/sda1']) - def test_make_partition(self): + def test_make_partition_sfdisk_v213(self): mock_run = self.mock_patch_object(self.partition_utils.utils, 'run_command') + mock_get_version = self.mock_patch_object( + self.partition_utils, '_get_sfdisk_version') + mock_get_version.return_value = '2.13' self.partition_utils.make_partition('session', 'dev', 'start', '-') + mock_get_version.assert_called_with() mock_run.assert_called_with(['sfdisk', '-uS', '/dev/dev'], 'start,;\n') + + def test_make_partition_sfdisk_v223(self): + mock_run = self.mock_patch_object(self.partition_utils.utils, + 'run_command') + mock_get_version = self.mock_patch_object( + self.partition_utils, '_get_sfdisk_version') + mock_get_version.return_value = '2.23' + + self.partition_utils.make_partition('session', 'dev', 'start', '-') + + mock_get_version.assert_called_with() + mock_run.assert_called_with(['sfdisk', '--force', '-uS', '/dev/dev'], + 'start,;\n') + + def test_make_partition_sfdisk_v226(self): + mock_run = self.mock_patch_object(self.partition_utils.utils, + 'run_command') + mock_get_version = self.mock_patch_object( + self.partition_utils, '_get_sfdisk_version') + mock_get_version.return_value = '2.26' + + self.partition_utils.make_partition('session', 'dev', 'start', '-') + + mock_get_version.assert_called_with() + mock_run.assert_called_with(['sfdisk', '-uS', '/dev/dev'], 'start,;\n') + + def test_get_sfdisk_version_213pre7(self): + mock_run = self.mock_patch_object( + self.partition_utils.utils, 'run_command') + mock_run.return_value = 'sfdisk (util-linux 2.13-pre7)' + + version = self.partition_utils._get_sfdisk_version() + + mock_run.assert_called_with(['/sbin/sfdisk', '-v']) + self.assertEqual(version, '2.13') + + def test_get_sfdisk_version_223(self): + mock_run = self.mock_patch_object( + self.partition_utils.utils, 'run_command') + mock_run.return_value = 'sfdisk from util-linux 2.23.2\n' + + version = self.partition_utils._get_sfdisk_version() + + mock_run.assert_called_with(['/sbin/sfdisk', '-v']) + self.assertEqual(version, '2.23')