summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Bcfg2/Client/Tools/POSIXUsers.py45
-rw-r--r--src/lib/Bcfg2/Server/Plugins/GroupPatterns.py23
-rw-r--r--src/lib/Bcfg2/Utils.py67
-rw-r--r--testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py38
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py21
-rw-r--r--testsuite/Testsrc/Testlib/TestUtils.py48
6 files changed, 127 insertions, 115 deletions
diff --git a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
index 7c8a4d578..849785e4a 100644
--- a/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
+++ b/src/lib/Bcfg2/Client/Tools/POSIXUsers.py
@@ -5,44 +5,9 @@ import sys
import pwd
import grp
import subprocess
+from Bcfg2.Utils import PackedDigitRange
import Bcfg2.Client.XML
import Bcfg2.Client.Tools
-from Bcfg2.Compat import any # pylint: disable=W0622
-
-
-class IDRangeSet(object):
- """ Representation of a set of integer ranges. Used to describe
- which UID/GID ranges are managed or unmanaged. """
-
- def __init__(self, *ranges):
- self.ranges = []
- self.ints = []
- self.str = ",".join(str(r) for r in ranges)
- for item in ranges:
- item = str(item).strip()
- if item.endswith("-"):
- self.ranges.append((int(item[:-1]), None))
- elif '-' in str(item):
- self.ranges.append(tuple(int(x) for x in item.split('-')))
- else:
- self.ints.append(int(item))
-
- def __contains__(self, other):
- other = int(other)
- if other in self.ints:
- return True
- return any((end is None and other >= start) or
- (end is not None and other >= start and other <= end)
- for start, end in self.ranges)
-
- def __repr__(self):
- return "%s:%s" % (self.__class__.__name__, str(self))
-
- def __str__(self):
- return "[%s]" % self.str
-
- def __len__(self):
- return len(self.ranges) + len(self.ints)
class ExecutionError(Exception):
@@ -124,16 +89,16 @@ class POSIXUsers(Bcfg2.Client.Tools.Tool):
self._blacklist = dict(POSIXUser=None, POSIXGroup=None)
if self.setup['posix_uid_whitelist']:
self._whitelist['POSIXUser'] = \
- IDRangeSet(*self.setup['posix_uid_whitelist'])
+ PackedDigitRange(*self.setup['posix_uid_whitelist'])
else:
self._blacklist['POSIXUser'] = \
- IDRangeSet(*self.setup['posix_uid_blacklist'])
+ PackedDigitRange(*self.setup['posix_uid_blacklist'])
if self.setup['posix_gid_whitelist']:
self._whitelist['POSIXGroup'] = \
- IDRangeSet(*self.setup['posix_gid_whitelist'])
+ PackedDigitRange(*self.setup['posix_gid_whitelist'])
else:
self._blacklist['POSIXGroup'] = \
- IDRangeSet(*self.setup['posix_gid_blacklist'])
+ PackedDigitRange(*self.setup['posix_gid_blacklist'])
@property
def existing(self):
diff --git a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
index 1b12e590a..5716a134f 100644
--- a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
@@ -6,28 +6,7 @@ import sys
import logging
import Bcfg2.Server.Lint
import Bcfg2.Server.Plugin
-from Bcfg2.Compat import any # pylint: disable=W0622
-
-
-class PackedDigitRange(object):
- """ Helper object for NameRange entries """
-
- def __init__(self, digit_range):
- self.sparse = list()
- self.ranges = list()
- for item in digit_range.split(','):
- if '-' in item:
- self.ranges.append(tuple([int(x) for x in item.split('-')]))
- else:
- self.sparse.append(int(item))
-
- def includes(self, other):
- """ return True if other is included in this range """
- iother = int(other)
- if iother in self.sparse:
- return True
- return any(iother in range(start, end + 1)
- for start, end in self.ranges)
+from Bcfg2.Utils import PackedDigitRange
class PatternMap(object):
diff --git a/src/lib/Bcfg2/Utils.py b/src/lib/Bcfg2/Utils.py
new file mode 100644
index 000000000..ba17e1a63
--- /dev/null
+++ b/src/lib/Bcfg2/Utils.py
@@ -0,0 +1,67 @@
+""" Miscellaneous useful utility functions, classes, etc., that are
+used by both client and server. Stuff that doesn't fit anywhere
+else. """
+
+from Bcfg2.Compat import any # pylint: disable=W0622
+
+
+class PackedDigitRange(object):
+ """ Representation of a set of integer ranges. A range is
+ described by a comma-delimited string of integers and ranges,
+ e.g.::
+
+ 1,10-12,15-20
+
+ Ranges are inclusive on both bounds, and may include 0. Negative
+ numbers are not supported."""
+
+ def __init__(self, *ranges):
+ """ May be instantiated in one of two ways::
+
+ PackedDigitRange(<comma-delimited list of ranges>)
+
+ Or::
+
+ PackedDigitRange(<int_or_range>[, <int_or_range>[, ...]])
+
+ E.g., both of the following are valid::
+
+ PackedDigitRange("1-5,7, 10-12")
+ PackedDigitRange("1-5", 7, "10-12")
+ """
+ self.ranges = []
+ self.ints = []
+ self.str = ",".join(str(r) for r in ranges)
+ if len(ranges) == 1 and "," in ranges[0]:
+ ranges = ranges[0].split(",")
+ for item in ranges:
+ item = str(item).strip()
+ if item.endswith("-"):
+ self.ranges.append((int(item[:-1]), None))
+ elif '-' in str(item):
+ self.ranges.append(tuple(int(x) for x in item.split('-')))
+ else:
+ self.ints.append(int(item))
+
+ def includes(self, other):
+ """ Return True if ``other`` is included in this range.
+ Functionally equivalent to ``other in range``, which should be
+ used instead. """
+ return other in self
+
+ def __contains__(self, other):
+ other = int(other)
+ if other in self.ints:
+ return True
+ return any((end is None and other >= start) or
+ (end is not None and other >= start and other <= end)
+ for start, end in self.ranges)
+
+ def __repr__(self):
+ return "%s:%s" % (self.__class__.__name__, str(self))
+
+ def __str__(self):
+ return "[%s]" % self.str
+
+ def __len__(self):
+ return sum(r[1] - r[0] + 1 for r in self.ranges) + len(self.ints)
diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
index bcf6cf133..8ab279a50 100644
--- a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
+++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
@@ -6,6 +6,7 @@ import subprocess
from mock import Mock, MagicMock, patch
import Bcfg2.Client.Tools
from Bcfg2.Client.Tools.POSIXUsers import *
+from Bcfg2.Utils import PackedDigitRange
# add all parent testsuite directories to sys.path to allow (most)
# relative imports in python 2.4
@@ -19,33 +20,6 @@ while path != "/":
from common import *
-class TestIDRangeSet(Bcfg2TestCase):
- def test_ranges(self):
- # test cases. tuples of (ranges, included numbers, excluded
- # numbers)
- # tuples of (range description, numbers that are included,
- # numebrs that are excluded)
- tests = [(["0-3"], ["0", 1, "2", 3], [4]),
- (["1"], [1], [0, "2"]),
- (["10-11"], [10, 11], [0, 1]),
- (["9-9"], [9], [8, 10]),
- (["0-100"], [0, 10, 99, 100], []),
- (["1", "3", "5"], [1, 3, 5], [0, 2, 4, 6]),
- (["1-5", "7"], [1, 3, 5, 7], [0, 6, 8]),
- (["1-5", 7, "9-11"], [1, 3, 5, 7, 9, 11], [0, 6, 8, 12]),
- (["852-855", "321-497", 763], [852, 855, 321, 400, 497, 763],
- [851, 320, 766, 999]),
- (["0-"], [0, 1, 100, 100000], []),
- ([1, "5-10", "1000-"], [1, 5, 10, 1000, 10000000],
- [4, 11, 999])]
- for ranges, inc, exc in tests:
- rng = IDRangeSet(*ranges)
- for test in inc:
- self.assertIn(test, rng)
- for test in exc:
- self.assertNotIn(test, rng)
-
-
class TestExecutor(Bcfg2TestCase):
test_obj = Executor
@@ -177,19 +151,19 @@ class TestPOSIXUsers(Bcfg2TestCase):
def test__in_managed_range(self):
users = self.get_obj()
- users._whitelist = dict(POSIXGroup=IDRangeSet("1-10"))
- users._blacklist = dict(POSIXGroup=IDRangeSet("8-100"))
+ users._whitelist = dict(POSIXGroup=PackedDigitRange("1-10"))
+ users._blacklist = dict(POSIXGroup=PackedDigitRange("8-100"))
self.assertTrue(users._in_managed_range("POSIXGroup", "9"))
users._whitelist = dict(POSIXGroup=None)
- users._blacklist = dict(POSIXGroup=IDRangeSet("8-100"))
+ users._blacklist = dict(POSIXGroup=PackedDigitRange("8-100"))
self.assertFalse(users._in_managed_range("POSIXGroup", "9"))
users._whitelist = dict(POSIXGroup=None)
- users._blacklist = dict(POSIXGroup=IDRangeSet("100-"))
+ users._blacklist = dict(POSIXGroup=PackedDigitRange("100-"))
self.assertTrue(users._in_managed_range("POSIXGroup", "9"))
- users._whitelist = dict(POSIXGroup=IDRangeSet("1-10"))
+ users._whitelist = dict(POSIXGroup=PackedDigitRange("1-10"))
users._blacklist = dict(POSIXGroup=None)
self.assertFalse(users._in_managed_range("POSIXGroup", "25"))
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py
index a7a6b3d6e..a9346156c 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py
@@ -18,27 +18,6 @@ from common import *
from TestPlugin import TestXMLFileBacked, TestPlugin, TestConnector
-class TestPackedDigitRange(Bcfg2TestCase):
- def test_includes(self):
- # tuples of (range description, numbers that are included,
- # numebrs that are excluded)
- tests = [("1-3", [1, "2", 3], [4]),
- ("1", [1], [0, "2"]),
- ("10-11", [10, 11], [0, 1]),
- ("9-9", [9], [8, 10]),
- ("0-100", [0, 10, 99, 100], []),
- ("1,3,5", [1, 3, 5], [0, 2, 4, 6]),
- ("1-5,7", [1, 3, 5, 7], [0, 6, 8]),
- ("1-5,7,9-11", [1, 3, 5, 7, 9, 11], [0, 6, 8, 12]),
- ("852-855,321-497,763", [852, 855, 321, 400, 497, 763], [])]
- for rng, inc, exc in tests:
- r = PackedDigitRange(rng)
- for test in inc:
- self.assertTrue(r.includes(test))
- for test in exc:
- self.assertFalse(r.includes(test))
-
-
class TestPatternMap(Bcfg2TestCase):
def test_ranges(self):
""" test processing NameRange patterns """
diff --git a/testsuite/Testsrc/Testlib/TestUtils.py b/testsuite/Testsrc/Testlib/TestUtils.py
new file mode 100644
index 000000000..349d6cd40
--- /dev/null
+++ b/testsuite/Testsrc/Testlib/TestUtils.py
@@ -0,0 +1,48 @@
+import os
+import sys
+import copy
+import lxml.etree
+import subprocess
+from mock import Mock, MagicMock, patch
+from Bcfg2.Utils import *
+
+# add all parent testsuite directories to sys.path to allow (most)
+# relative imports in python 2.4
+path = os.path.dirname(__file__)
+while path != "/":
+ if os.path.basename(path).lower().startswith("test"):
+ sys.path.append(path)
+ if os.path.basename(path) == "testsuite":
+ break
+ path = os.path.dirname(path)
+from common import *
+
+
+class TestPackedDigitRange(Bcfg2TestCase):
+ def test_ranges(self):
+ # test cases. tuples of (ranges, included numbers, excluded
+ # numbers)
+ # tuples of (range description, numbers that are included,
+ # numebrs that are excluded)
+ tests = [(["0-3"], ["0", 1, "2", 3], [4]),
+ (["1"], [1], [0, "2"]),
+ (["10-11"], [10, 11], [0, 1]),
+ (["9-9"], [9], [8, 10]),
+ (["0-100"], [0, 10, 99, 100], []),
+ (["1", "3", "5"], [1, 3, 5], [0, 2, 4, 6]),
+ (["1-5", "7"], [1, 3, 5, 7], [0, 6, 8]),
+ (["1-5", 7, "9-11"], [1, 3, 5, 7, 9, 11], [0, 6, 8, 12]),
+ (["1-5, 7,9-11 "], [1, 3, 5, 7, 9, 11], [0, 6, 8, 12]),
+ (["852-855", "321-497", 763], [852, 855, 321, 400, 497, 763],
+ [851, 320, 766, 999]),
+ (["0-"], [0, 1, 100, 100000], []),
+ ([1, "5-10", "1000-"], [1, 5, 10, 1000, 10000000],
+ [4, 11, 999])]
+ for ranges, inc, exc in tests:
+ rng = PackedDigitRange(*ranges)
+ for test in inc:
+ self.assertIn(test, rng)
+ self.assertTrue(rng.includes(test))
+ for test in exc:
+ self.assertNotIn(test, rng)
+ self.assertFalse(rng.includes(test))