Revision bbfed756

b/lib/utils/text.py
74 74
  if not case_sensitive:
75 75
    re_flags |= re.IGNORECASE
76 76
    key = key.upper()
77
  mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
77

  
78
  name_re = re.compile(r"^%s(\..*)?$" % re.escape(key), re_flags)
79

  
78 80
  names_filtered = []
79 81
  string_matches = []
80 82
  for name in name_list:
81
    if mo.match(name) is not None:
83
    if name_re.match(name) is not None:
82 84
      names_filtered.append(name)
83 85
      if not case_sensitive and key == name.upper():
84 86
        string_matches.append(name)
......
87 89
    return string_matches[0]
88 90
  if len(names_filtered) == 1:
89 91
    return names_filtered[0]
92

  
90 93
  return None
91 94

  
92 95

  
96
def _DnsNameGlobHelper(match):
97
  """Helper function for L{DnsNameGlobPattern}.
98

  
99
  Returns regular expression pattern for parts of the pattern.
100

  
101
  """
102
  text = match.group(0)
103

  
104
  if text == "*":
105
    return "[^.]*"
106
  elif text == "?":
107
    return "[^.]"
108
  else:
109
    return re.escape(text)
110

  
111

  
112
def DnsNameGlobPattern(pattern):
113
  """Generates regular expression from DNS name globbing pattern.
114

  
115
  A DNS name globbing pattern (e.g. C{*.site}) is converted to a regular
116
  expression. Escape sequences or ranges (e.g. [a-z]) are not supported.
117

  
118
  Matching always starts at the leftmost part. An asterisk (*) matches all
119
  characters except the dot (.) separating DNS name parts. A question mark (?)
120
  matches a single character except the dot (.).
121

  
122
  @type pattern: string
123
  @param pattern: DNS name globbing pattern
124
  @rtype: string
125
  @return: Regular expression
126

  
127
  """
128
  return r"^%s(\..*)?$" % re.sub(r"\*|\?|[^*?]*", _DnsNameGlobHelper, pattern)
129

  
130

  
93 131
def FormatUnit(value, units):
94 132
  """Formats an incoming number of MiB with the appropriate unit.
95 133

  
b/test/ganeti.utils.text_unittest.py
106 106
                     None)
107 107

  
108 108

  
109
class TestDnsNameGlobPattern(unittest.TestCase):
110
  def setUp(self):
111
    self.names = [
112
      "node1.example.com",
113
      "node2-0.example.com",
114
      "node2-1.example.com",
115
      "node1.example.net",
116
      "web1.example.com",
117
      "web2.example.com",
118
      "sub.site.example.com",
119
      ]
120

  
121
  def _Test(self, pattern):
122
    re_pat = utils.DnsNameGlobPattern(pattern)
123

  
124
    return filter(re.compile(re_pat).match, self.names)
125

  
126
  def test(self):
127
    for pattern in ["xyz", "node", " ", "example.net", "x*.example.*",
128
                    "x*.example.com"]:
129
      self.assertEqual(self._Test(pattern), [])
130

  
131
    for pattern in ["*", "???*"]:
132
      self.assertEqual(self._Test(pattern), self.names)
133

  
134
    self.assertEqual(self._Test("node1.*.net"), ["node1.example.net"])
135
    self.assertEqual(self._Test("*.example.net"), ["node1.example.net"])
136
    self.assertEqual(self._Test("web1.example.com"), ["web1.example.com"])
137

  
138
    for pattern in ["*.*.*.*", "???", "*.site"]:
139
      self.assertEqual(self._Test(pattern), ["sub.site.example.com"])
140

  
141
    self.assertEqual(self._Test("node1"), [
142
      "node1.example.com",
143
      "node1.example.net",
144
      ])
145
    self.assertEqual(self._Test("node?*.example.*"), [
146
      "node1.example.com",
147
      "node2-0.example.com",
148
      "node2-1.example.com",
149
      "node1.example.net",
150
      ])
151
    self.assertEqual(self._Test("*-?"), [
152
      "node2-0.example.com",
153
      "node2-1.example.com",
154
      ])
155
    self.assertEqual(self._Test("node2-?.example.com"), [
156
      "node2-0.example.com",
157
      "node2-1.example.com",
158
      ])
159

  
160

  
109 161
class TestFormatUnit(unittest.TestCase):
110 162
  """Test case for the FormatUnit function"""
111 163

  

Also available in: Unified diff