diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py
index d0df82173c8df6ea0b7a6a26191aefbe4fa7d4a9..2f2da51e23dd33de47400ff02b879af7457c63c4 100644
--- a/lib/utils/__init__.py
+++ b/lib/utils/__init__.py
@@ -255,6 +255,32 @@ def ParseCpuMask(cpu_mask):
return cpu_list
+def ParseMultiCpuMask(cpu_mask):
+ """Parse a multiple CPU mask definition and return the list of CPU IDs.
+
+ CPU mask format: colon-separated list of comma-separated list of CPU IDs
+ or dash-separated ID ranges, with optional "all" as CPU value
+ Example: "0-2,5:all:1,5,6:2" -> [ [ 0,1,2,5 ], [ -1 ], [ 1, 5, 6 ], [ 2 ] ]
+
+ @type cpu_mask: str
+ @param cpu_mask: multiple CPU mask definition
+ @rtype: list of lists of int
+ @return: list of lists of CPU IDs
+
+ """
+ if not cpu_mask:
+ return []
+ cpu_list = []
+ for range_def in cpu_mask.split(constants.CPU_PINNING_SEP):
+ if range_def == constants.CPU_PINNING_ALL:
+ cpu_list.append([constants.CPU_PINNING_ALL_VAL, ])
+ else:
+ # Uniquify and sort the list before adding
+ cpu_list.append(sorted(set(ParseCpuMask(range_def))))
+
+ return cpu_list
+
+
def GetHomeDir(user, default=None):
"""Try to get the homedir of the given user.
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index e557b2be1eb069f6d6caf0ff0f3a9bf0ace03b3e..80e737c771e5d2c034c5170e739d3cd5ae0ef72f 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -61,6 +61,22 @@ class TestParseCpuMask(unittest.TestCase):
self.assertRaises(errors.ParseError, utils.ParseCpuMask, data)
+class TestParseMultiCpuMask(unittest.TestCase):
+ """Test case for the ParseMultiCpuMask function."""
+
+ def testWellFormed(self):
+ self.assertEqual(utils.ParseMultiCpuMask(""), [])
+ self.assertEqual(utils.ParseMultiCpuMask("1"), [[1]])
+ self.assertEqual(utils.ParseMultiCpuMask("0-2,4,5-5"), [[0, 1, 2, 4, 5]])
+ self.assertEqual(utils.ParseMultiCpuMask("all"), [[-1]])
+ self.assertEqual(utils.ParseMultiCpuMask("0-2:all:4,6-8"),
+ [[0, 1, 2], [-1], [4, 6, 7, 8]])
+
+ def testInvalidInput(self):
+ for data in ["garbage", "0,", "0-1-2", "2-1", "1-a", "all-all"]:
+ self.assertRaises(errors.ParseError, utils.ParseCpuMask, data)
+
+
class TestGetMounts(unittest.TestCase):
"""Test case for GetMounts()."""