示例#1
0
 def testGlob(self):
   self.assertEqual(qlang.MakeFilter(["*.site"], False),
                    [qlang.OP_OR, [qlang.OP_REGEXP, "name",
                                   utils.DnsNameGlobPattern("*.site")]])
   self.assertEqual(qlang.MakeFilter(["web?.example"], False),
                    [qlang.OP_OR, [qlang.OP_REGEXP, "name",
                                   utils.DnsNameGlobPattern("web?.example")]])
   self.assertEqual(qlang.MakeFilter(["*.a", "*.b", "?.c"], False),
                    [qlang.OP_OR,
                     [qlang.OP_REGEXP, "name",
                      utils.DnsNameGlobPattern("*.a")],
                     [qlang.OP_REGEXP, "name",
                      utils.DnsNameGlobPattern("*.b")],
                     [qlang.OP_REGEXP, "name",
                      utils.DnsNameGlobPattern("?.c")]])
示例#2
0
def _MakeFilterPart(namefield, text, isnumeric=False):
    """Generates filter for one argument.

  """
    if isnumeric:
        try:
            number = int(text)
        except (TypeError, ValueError) as err:
            raise errors.OpPrereqError("Invalid job ID passed: %s" % str(err),
                                       errors.ECODE_INVAL)
        return [OP_EQUAL, namefield, number]
    elif _CheckGlobbing(text):
        return [OP_REGEXP, namefield, utils.DnsNameGlobPattern(text)]
    else:
        return [OP_EQUAL, namefield, text]
示例#3
0
  def testFilter(self):
    self.assertEqual(qlang.MakeFilter(["foo/bar"], False),
                     [qlang.OP_TRUE, "foo/bar"])
    self.assertEqual(qlang.MakeFilter(["foo=='bar'"], False),
                     [qlang.OP_EQUAL, "foo", "bar"])
    self.assertEqual(qlang.MakeFilter(["field=*'*.site'"], False),
                     [qlang.OP_REGEXP, "field",
                      utils.DnsNameGlobPattern("*.site")])

    # Plain name parses as name filter, not boolean
    for name in ["node1", "n-o-d-e", "n_o_d_e", "node1.example.com",
                 "node1.example.com."]:
      self.assertEqual(qlang.MakeFilter([name], False),
                       [qlang.OP_OR, [qlang.OP_EQUAL, "name", name]])

    # Invalid filters
    for i in ["foo==bar", "foo+=1"]:
      self.assertRaises(errors.QueryFilterParseError,
                        qlang.MakeFilter, [i], False)
示例#4
0
def BuildFilterParser():
    """Builds a parser for query filter strings.

  @rtype: pyparsing.ParserElement

  """
    field_name = pyp.Word(pyp.alphas, pyp.alphanums + "_/.")

    # Integer
    num_sign = pyp.Word("-+", exact=1)
    number = pyp.Combine(pyp.Optional(num_sign) + pyp.Word(pyp.nums))
    number.setParseAction(lambda toks: int(toks[0]))

    quoted_string = pyp.quotedString.copy().setParseAction(pyp.removeQuotes)

    # Right-hand-side value
    rval = (number | quoted_string)

    # Boolean condition
    bool_cond = field_name.copy()
    bool_cond.setParseAction(lambda (fname, ): [[OP_TRUE, fname]])

    # Simple binary conditions
    binopstbl = {
        "==": OP_EQUAL,
        "!=": OP_NOT_EQUAL,
        "<": OP_LT,
        "<=": OP_LE,
        ">": OP_GT,
        ">=": OP_GE,
    }

    binary_cond = (field_name + pyp.oneOf(binopstbl.keys()) + rval)
    binary_cond.setParseAction(lambda
                               (lhs, op, rhs): [[binopstbl[op], lhs, rhs]])

    # "in" condition
    in_cond = (rval + pyp.Suppress("in") + field_name)
    in_cond.setParseAction(lambda
                           (value, field): [[OP_CONTAINS, field, value]])

    # "not in" condition
    not_in_cond = (rval + pyp.Suppress("not") + pyp.Suppress("in") +
                   field_name)
    not_in_cond.setParseAction(
        lambda (value, field): [[OP_NOT, [OP_CONTAINS, field, value]]])

    # Regular expression, e.g. m/foobar/i
    regexp_val = pyp.Group(
        pyp.Optional("m").suppress() + pyp.MatchFirst(
            [pyp.QuotedString(i, escChar="\\") for i in _KNOWN_REGEXP_DELIM]) +
        pyp.Optional(pyp.Word(pyp.alphas), default=""))
    regexp_val.setParseAction(_ConvertRegexpValue)
    regexp_cond = (field_name + pyp.Suppress("=~") + regexp_val)
    regexp_cond.setParseAction(lambda
                               (field, value): [[OP_REGEXP, field, value]])

    not_regexp_cond = (field_name + pyp.Suppress("!~") + regexp_val)
    not_regexp_cond.setParseAction(
        lambda (field, value): [[OP_NOT, [OP_REGEXP, field, value]]])

    # Globbing, e.g. name =* "*.site"
    glob_cond = (field_name + pyp.Suppress("=*") + quoted_string)
    glob_cond.setParseAction(
        lambda (field, value):
        [[OP_REGEXP, field, utils.DnsNameGlobPattern(value)]])

    not_glob_cond = (field_name + pyp.Suppress("!*") + quoted_string)
    not_glob_cond.setParseAction(
        lambda (field, value):
        [[OP_NOT, [OP_REGEXP, field,
                   utils.DnsNameGlobPattern(value)]]])

    # All possible conditions
    condition = (binary_cond ^ bool_cond ^ in_cond ^ not_in_cond ^ regexp_cond
                 ^ not_regexp_cond ^ glob_cond ^ not_glob_cond)

    # Associativity operators
    filter_expr = pyp.operatorPrecedence(condition, [
        (pyp.Keyword("not").suppress(), 1, pyp.opAssoc.RIGHT,
         lambda toks: [[OP_NOT, toks[0][0]]]),
        (pyp.Keyword("and").suppress(), 2, pyp.opAssoc.LEFT,
         _ConvertLogicOp(OP_AND)),
        (pyp.Keyword("or").suppress(), 2, pyp.opAssoc.LEFT,
         _ConvertLogicOp(OP_OR)),
    ])

    parser = pyp.StringStart() + filter_expr + pyp.StringEnd()
    parser.parseWithTabs()

    # Originally C{parser.validate} was called here, but there seems to be some
    # issue causing it to fail whenever the "not" operator is included above.

    return parser
示例#5
0
    return bool(frozenset(text) & GLOB_DETECTION_CHARS)


def _MakeFilterPart(namefield, text, isnumeric=False):
    """Generates filter for one argument.

  """
    if isnumeric:
        try:
            number = int(text)
        except (TypeError, ValueError), err:
            raise errors.OpPrereqError("Invalid job ID passed: %s" % str(err),
                                       errors.ECODE_INVAL)
        return [OP_EQUAL, namefield, number]
    elif _CheckGlobbing(text):
        return [OP_REGEXP, namefield, utils.DnsNameGlobPattern(text)]
    else:
        return [OP_EQUAL, namefield, text]


def MakeFilter(args, force_filter, namefield=None, isnumeric=False):
    """Try to make a filter from arguments to a command.

  If the name could be a filter it is parsed as such. If it's just a globbing
  pattern, e.g. "*.site", such a filter is constructed. As a last resort the
  names are treated just as a plain name filter.

  @type args: list of string
  @param args: Arguments to command
  @type force_filter: bool
  @param force_filter: Whether to force treatment as a full-fledged filter
示例#6
0
    def test(self):
        self._Test("name==\"foobar\"", [qlang.OP_EQUAL, "name", "foobar"])
        self._Test("name=='foobar'", [qlang.OP_EQUAL, "name", "foobar"])

        # Legacy "="
        self._Test("name=\"foobar\"", [qlang.OP_EQUAL, "name", "foobar"])
        self._Test("name='foobar'", [qlang.OP_EQUAL, "name", "foobar"])

        self._Test("valA==1 and valB==2 or valC==3", [
            qlang.OP_OR,
            [
                qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
                [qlang.OP_EQUAL, "valB", 2]
            ], [qlang.OP_EQUAL, "valC", 3]
        ])

        self._Test(("(name\n==\"foobar\") and (xyz==\"va)ue\" and k == 256 or"
                    " x ==\t\"y\"\n) and mc"), [
                        qlang.OP_AND, [qlang.OP_EQUAL, "name", "foobar"],
                        [
                            qlang.OP_OR,
                            [
                                qlang.OP_AND, [qlang.OP_EQUAL, "xyz", "va)ue"],
                                [qlang.OP_EQUAL, "k", 256]
                            ], [qlang.OP_EQUAL, "x", "y"]
                        ], [qlang.OP_TRUE, "mc"]
                    ])

        self._Test("(xyz==\"v\" or k == 256 and x == \"y\")", [
            qlang.OP_OR, [qlang.OP_EQUAL, "xyz", "v"],
            [
                qlang.OP_AND, [qlang.OP_EQUAL, "k", 256],
                [qlang.OP_EQUAL, "x", "y"]
            ]
        ])

        self._Test("valA==1 and valB==2 and valC==3", [
            qlang.OP_AND, [qlang.OP_EQUAL, "valA", 1],
            [qlang.OP_EQUAL, "valB", 2], [qlang.OP_EQUAL, "valC", 3]
        ])
        self._Test(
            "master or field",
            [qlang.OP_OR, [qlang.OP_TRUE, "master"], [qlang.OP_TRUE, "field"]])
        self._Test("mem == 128", [qlang.OP_EQUAL, "mem", 128])
        self._Test("negfield != -1", [qlang.OP_NOT_EQUAL, "negfield", -1])
        self._Test("master", [qlang.OP_TRUE, "master"], expect_filter=False)
        self._Test("not master", [qlang.OP_NOT, [qlang.OP_TRUE, "master"]])
        for op in ["not", "and", "or"]:
            self._Test("%sxyz" % op,
                       [qlang.OP_TRUE, "%sxyz" % op],
                       expect_filter=False)
            self._Test(
                "not %sxyz" % op,
                [qlang.OP_NOT, [qlang.OP_TRUE, "%sxyz" % op]])
            self._Test(
                "  not \t%sfoo" % op,
                [qlang.OP_NOT, [qlang.OP_TRUE, "%sfoo" % op]])
            self._Test("%sname =~ m/abc/" % op,
                       [qlang.OP_REGEXP, "%sname" % op, "abc"])
        self._Test("master and not other", [
            qlang.OP_AND, [qlang.OP_TRUE, "master"],
            [qlang.OP_NOT, [qlang.OP_TRUE, "other"]]
        ])
        self._Test("not (master or other == 4)", [
            qlang.OP_NOT,
            [
                qlang.OP_OR, [qlang.OP_TRUE, "master"],
                [qlang.OP_EQUAL, "other", 4]
            ]
        ])
        self._Test("some==\"val\\\"ue\"",
                   [qlang.OP_EQUAL, "some", "val\\\"ue"])
        self._Test("123 in ips", [qlang.OP_CONTAINS, "ips", 123])
        self._Test("99 not in ips",
                   [qlang.OP_NOT, [qlang.OP_CONTAINS, "ips", 99]])
        self._Test("\"a\" in valA and \"b\" not in valB", [
            qlang.OP_AND, [qlang.OP_CONTAINS, "valA", "a"],
            [qlang.OP_NOT, [qlang.OP_CONTAINS, "valB", "b"]]
        ])

        self._Test("name =~ m/test/", [qlang.OP_REGEXP, "name", "test"])
        self._Test("name =~ m/^node.*example.com$/i",
                   [qlang.OP_REGEXP, "name", "(?i)^node.*example.com$"])
        self._Test(
            "(name =~ m/^node.*example.com$/s and master) or pip =~ |^3.*|", [
                qlang.OP_OR,
                [
                    qlang.OP_AND,
                    [qlang.OP_REGEXP, "name", "(?s)^node.*example.com$"],
                    [qlang.OP_TRUE, "master"]
                ], [qlang.OP_REGEXP, "pip", "^3.*"]
            ])
        for flags in ["si", "is", "ssss", "iiiisiii"]:
            self._Test(
                "name =~ m/gi/%s" % flags,
                [qlang.OP_REGEXP, "name",
                 "(?%s)gi" % "".join(sorted(flags))])

        for i in qlang._KNOWN_REGEXP_DELIM:
            self._Test("name =~ m%stest%s" % (i, i),
                       [qlang.OP_REGEXP, "name", "test"])
            self._Test("name !~ m%stest%s" % (i, i),
                       [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
            self._Test("not\tname =~ m%stest%s" % (i, i),
                       [qlang.OP_NOT, [qlang.OP_REGEXP, "name", "test"]])
            self._Test("notname =~ m%stest%s" % (i, i),
                       [qlang.OP_REGEXP, "notname", "test"])

        self._Test(
            "name =* '*.site'",
            [qlang.OP_REGEXP, "name",
             utils.DnsNameGlobPattern("*.site")])
        self._Test("field !* '*.example.*'", [
            qlang.OP_NOT,
            [
                qlang.OP_REGEXP, "field",
                utils.DnsNameGlobPattern("*.example.*")
            ]
        ])

        self._Test("ctime < 1234", [qlang.OP_LT, "ctime", 1234])
        self._Test("ctime > 1234", [qlang.OP_GT, "ctime", 1234])
        self._Test("mtime <= 9999", [qlang.OP_LE, "mtime", 9999])
        self._Test("mtime >= 9999", [qlang.OP_GE, "mtime", 9999])
    def _Test(self, pattern):
        re_pat = re.compile(utils.DnsNameGlobPattern(pattern))

        return [n for n in self.names if re_pat.match(n)]
示例#8
0
    def _Test(self, pattern):
        re_pat = utils.DnsNameGlobPattern(pattern)

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