Revision 3f2f55bb

b/lib/qlang.py
32 32
"""
33 33

  
34 34
import re
35
import string # pylint: disable-msg=W0402
35 36

  
36 37
import pyparsing as pyp
37 38

  
38 39
from ganeti import errors
40
from ganeti import netutils
39 41

  
40 42

  
41 43
# Logic operators with one or more operands, each of which is a filter on its
......
57 59
OP_CONTAINS = "=[]"
58 60

  
59 61

  
62
#: Characters used for detecting user-written filters (see L{MaybeFilter})
63
FILTER_DETECTION_CHARS = frozenset("()=/!~" + string.whitespace)
64

  
65

  
60 66
def MakeSimpleFilter(namefield, values):
61 67
  """Builds simple a filter.
62 68

  
......
220 226
  except pyp.ParseBaseException, err:
221 227
    raise errors.QueryFilterParseError("Failed to parse query filter"
222 228
                                       " '%s': %s" % (text, err), err)
229

  
230

  
231
def MaybeFilter(text):
232
  """Try to determine if a string is a filter or a name.
233

  
234
  If in doubt, this function treats a text as a name.
235

  
236
  @type text: string
237
  @param text: String to be examined
238
  @rtype: bool
239

  
240
  """
241
  # Quick check for punctuation and whitespace
242
  if frozenset(text) & FILTER_DETECTION_CHARS:
243
    return True
244

  
245
  try:
246
    netutils.Hostname.GetNormalizedName(text)
247
  except errors.OpPrereqError:
248
    # Not a valid hostname, treat as filter
249
    return True
250

  
251
  # Most probably a name
252
  return False
b/test/ganeti.qlang_unittest.py
22 22
"""Script for testing ganeti.qlang"""
23 23

  
24 24
import unittest
25
import string
25 26

  
26 27
from ganeti import utils
27 28
from ganeti import errors
......
52 53
  def setUp(self):
53 54
    self.parser = qlang.BuildFilterParser()
54 55

  
55
  def _Test(self, filter_, expected):
56
  def _Test(self, filter_, expected, expect_filter=True):
57
    if expect_filter:
58
      self.assertTrue(qlang.MaybeFilter(filter_),
59
                      msg="'%s' was not recognized as a filter" % filter_)
60
    else:
61
      self.assertFalse(qlang.MaybeFilter(filter_),
62
                       msg=("'%s' should not be recognized as a filter" %
63
                            filter_))
56 64
    self.assertEqual(qlang.ParseFilter(filter_, parser=self.parser), expected)
57 65

  
58 66
  def test(self):
......
90 98
                             [qlang.OP_TRUE, "field"]])
91 99
    self._Test("mem == 128", [qlang.OP_EQUAL, "mem", 128])
92 100
    self._Test("negfield != -1", [qlang.OP_NOT_EQUAL, "negfield", -1])
93
    self._Test("master", [qlang.OP_TRUE, "master"])
101
    self._Test("master", [qlang.OP_TRUE, "master"],
102
               expect_filter=False)
94 103
    self._Test("not master", [qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
95 104
    for op in ["not", "and", "or"]:
96
      self._Test("%sxyz" % op, [qlang.OP_TRUE, "%sxyz" % op])
105
      self._Test("%sxyz" % op, [qlang.OP_TRUE, "%sxyz" % op],
106
                 expect_filter=False)
97 107
      self._Test("not %sxyz" % op,
98 108
                 [qlang.OP_NOT, [qlang.OP_TRUE, "%sxyz" % op]])
99 109
      self._Test("  not \t%sfoo" % op,
......
166 176
        self.fail("Invalid filter '%s' did not raise exception" % filter_)
167 177

  
168 178

  
179
class TestMaybeFilter(unittest.TestCase):
180
  def test(self):
181
    self.assertTrue(qlang.MaybeFilter(""))
182
    self.assertTrue(qlang.MaybeFilter("foo/bar"))
183
    self.assertTrue(qlang.MaybeFilter("foo==bar"))
184

  
185
    for i in set("()!~" + string.whitespace) | qlang.FILTER_DETECTION_CHARS:
186
      self.assertTrue(qlang.MaybeFilter(i),
187
                      msg="%r not recognized as filter" % i)
188

  
189
    self.assertFalse(qlang.MaybeFilter("node1"))
190
    self.assertFalse(qlang.MaybeFilter("n-o-d-e"))
191
    self.assertFalse(qlang.MaybeFilter("n_o_d_e"))
192
    self.assertFalse(qlang.MaybeFilter("node1.example.com"))
193
    self.assertFalse(qlang.MaybeFilter("node1.example.com."))
194

  
195

  
169 196
if __name__ == "__main__":
170 197
  testutils.GanetiTestProgram()

Also available in: Unified diff