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"""