diff --git a/lib/errors.py b/lib/errors.py
index 8618be2be33d876aaf58a21e7e429b5218c492c1..f03d6590305edaf35df0e85b0ad191b07d55c5e2 100644
--- a/lib/errors.py
+++ b/lib/errors.py
@@ -228,6 +228,14 @@ class UnitParseError(GenericError):
   """
 
 
+class ParseError(GenericError):
+  """Generic parse error.
+
+  Raised when unable to parse user input.
+
+  """
+
+
 class TypeEnforcementError(GenericError):
   """Unable to enforce data type.
 
diff --git a/lib/utils.py b/lib/utils.py
index 6caa0fef5a0b08e1bf8e243bdbc17f1b41901425..f846f3b26de560ac92baa02177f3b1deb3a8fdc7 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -1299,6 +1299,45 @@ def ParseUnit(input_string):
   return value
 
 
+def ParseCpuMask(cpu_mask):
+  """Parse a CPU mask definition and return the list of CPU IDs.
+
+  CPU mask format: comma-separated list of CPU IDs
+  or dash-separated ID ranges
+  Example: "0-2,5" -> "0,1,2,5"
+
+  @type cpu_mask: str
+  @param cpu_mask: CPU mask definition
+  @rtype: list of int
+  @return: list of CPU IDs
+
+  """
+  if not cpu_mask:
+    return []
+  cpu_list = []
+  for range_def in cpu_mask.split(","):
+    boundaries = range_def.split("-")
+    n_elements = len(boundaries)
+    if n_elements > 2:
+      raise errors.ParseError("Invalid CPU ID range definition"
+                              " (only one hyphen allowed): %s" % range_def)
+    try:
+      lower = int(boundaries[0])
+    except (ValueError, TypeError), err:
+      raise errors.ParseError("Invalid CPU ID value for lower boundary of"
+                              " CPU ID range: %s" % str(err))
+    try:
+      higher = int(boundaries[-1])
+    except (ValueError, TypeError), err:
+      raise errors.ParseError("Invalid CPU ID value for higher boundary of"
+                              " CPU ID range: %s" % str(err))
+    if lower > higher:
+      raise errors.ParseError("Invalid CPU ID range definition"
+                              " (%d > %d): %s" % (lower, higher, range_def))
+    cpu_list.extend(range(lower, higher + 1))
+  return cpu_list
+
+
 def AddAuthorizedKey(file_name, key):
   """Adds an SSH public key to an authorized_keys file.
 
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 5ff5fc9f77c7236a2718ff25cc1de864c605cdc3..839838e867f8b4886fed53cb1b6d91ec845fa424 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -996,6 +996,28 @@ class TestParseUnit(unittest.TestCase):
       self.assertRaises(errors.UnitParseError, ParseUnit, '1,3' + suffix)
 
 
+class TestParseCpuMask(unittest.TestCase):
+  """Test case for the ParseCpuMask function."""
+
+  def testWellFormed(self):
+    self.assertEqual(utils.ParseCpuMask(""), [])
+    self.assertEqual(utils.ParseCpuMask("1"), [1])
+    self.assertEqual(utils.ParseCpuMask("0-2,4,5-5"), [0,1,2,4,5])
+
+  def testInvalidInput(self):
+    self.assertRaises(errors.ParseError,
+                      utils.ParseCpuMask,
+                      "garbage")
+    self.assertRaises(errors.ParseError,
+                      utils.ParseCpuMask,
+                      "0,")
+    self.assertRaises(errors.ParseError,
+                      utils.ParseCpuMask,
+                      "0-1-2")
+    self.assertRaises(errors.ParseError,
+                      utils.ParseCpuMask,
+                      "2-1")
+
 class TestSshKeys(testutils.GanetiTestCase):
   """Test case for the AddAuthorizedKey function"""