Commit bbfed756 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

utils: Add function generating regex for DNS name globbing



The intent of this function is to be able to provide a globbing operator
or query filters. One should be able to say, for example, something to
the effect of “gnt-instance shutdown '*.site'”.

Also rename a variable in MatchNameComponent.
Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent aef59ae7
......@@ -74,11 +74,13 @@ def MatchNameComponent(key, name_list, case_sensitive=True):
if not case_sensitive:
re_flags |= re.IGNORECASE
key = key.upper()
mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
name_re = re.compile(r"^%s(\..*)?$" % re.escape(key), re_flags)
names_filtered = []
string_matches = []
for name in name_list:
if mo.match(name) is not None:
if name_re.match(name) is not None:
names_filtered.append(name)
if not case_sensitive and key == name.upper():
string_matches.append(name)
......@@ -87,9 +89,45 @@ def MatchNameComponent(key, name_list, case_sensitive=True):
return string_matches[0]
if len(names_filtered) == 1:
return names_filtered[0]
return None
def _DnsNameGlobHelper(match):
"""Helper function for L{DnsNameGlobPattern}.
Returns regular expression pattern for parts of the pattern.
"""
text = match.group(0)
if text == "*":
return "[^.]*"
elif text == "?":
return "[^.]"
else:
return re.escape(text)
def DnsNameGlobPattern(pattern):
"""Generates regular expression from DNS name globbing pattern.
A DNS name globbing pattern (e.g. C{*.site}) is converted to a regular
expression. Escape sequences or ranges (e.g. [a-z]) are not supported.
Matching always starts at the leftmost part. An asterisk (*) matches all
characters except the dot (.) separating DNS name parts. A question mark (?)
matches a single character except the dot (.).
@type pattern: string
@param pattern: DNS name globbing pattern
@rtype: string
@return: Regular expression
"""
return r"^%s(\..*)?$" % re.sub(r"\*|\?|[^*?]*", _DnsNameGlobHelper, pattern)
def FormatUnit(value, units):
"""Formats an incoming number of MiB with the appropriate unit.
......
......@@ -106,6 +106,58 @@ class TestMatchNameComponent(unittest.TestCase):
None)
class TestDnsNameGlobPattern(unittest.TestCase):
def setUp(self):
self.names = [
"node1.example.com",
"node2-0.example.com",
"node2-1.example.com",
"node1.example.net",
"web1.example.com",
"web2.example.com",
"sub.site.example.com",
]
def _Test(self, pattern):
re_pat = utils.DnsNameGlobPattern(pattern)
return filter(re.compile(re_pat).match, self.names)
def test(self):
for pattern in ["xyz", "node", " ", "example.net", "x*.example.*",
"x*.example.com"]:
self.assertEqual(self._Test(pattern), [])
for pattern in ["*", "???*"]:
self.assertEqual(self._Test(pattern), self.names)
self.assertEqual(self._Test("node1.*.net"), ["node1.example.net"])
self.assertEqual(self._Test("*.example.net"), ["node1.example.net"])
self.assertEqual(self._Test("web1.example.com"), ["web1.example.com"])
for pattern in ["*.*.*.*", "???", "*.site"]:
self.assertEqual(self._Test(pattern), ["sub.site.example.com"])
self.assertEqual(self._Test("node1"), [
"node1.example.com",
"node1.example.net",
])
self.assertEqual(self._Test("node?*.example.*"), [
"node1.example.com",
"node2-0.example.com",
"node2-1.example.com",
"node1.example.net",
])
self.assertEqual(self._Test("*-?"), [
"node2-0.example.com",
"node2-1.example.com",
])
self.assertEqual(self._Test("node2-?.example.com"), [
"node2-0.example.com",
"node2-1.example.com",
])
class TestFormatUnit(unittest.TestCase):
"""Test case for the FormatUnit function"""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment