4 # Copyright (C) 2010, 2011 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Script for testing ganeti.query"""
28 from ganeti import constants
29 from ganeti import utils
30 from ganeti import compat
31 from ganeti import errors
32 from ganeti import query
33 from ganeti import objects
34 from ganeti import cmdlib
39 class TestConstants(unittest.TestCase):
41 self.assertEqual(set(query._VERIFY_FN.keys()),
46 def __init__(self, data, **kwargs):
49 for name, value in kwargs.items():
50 setattr(self, name, value)
53 return iter(self.data)
56 def _GetDiskSize(nr, ctx, item):
61 return query._FS_UNAVAIL
64 class TestQuery(unittest.TestCase):
66 (STATIC, DISK) = range(10, 12)
68 fielddef = query._PrepareFieldList([
69 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
70 STATIC, 0, lambda ctx, item: item["name"]),
71 (query._MakeField("master", "Master", constants.QFT_BOOL, "Master"),
72 STATIC, 0, lambda ctx, item: ctx.mastername == item["name"]),
74 [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
75 constants.QFT_UNIT, "Disk size %s" % i),
76 DISK, 0, compat.partial(_GetDiskSize, i))
77 for i in range(4)], [])
79 q = query.Query(fielddef, ["name"])
80 self.assertEqual(q.RequestedData(), set([STATIC]))
81 self.assertEqual(len(q._fields), 1)
82 self.assertEqual(len(q.GetFields()), 1)
83 self.assertEqual(q.GetFields()[0].ToDict(),
84 objects.QueryFieldDefinition(name="name",
86 kind=constants.QFT_TEXT,
89 # Create data only once query has been prepared
91 { "name": "node1", "disks": [0, 1, 2], },
92 { "name": "node2", "disks": [3, 4], },
93 { "name": "node3", "disks": [5, 6, 7], },
96 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
97 [[(constants.RS_NORMAL, "node1")],
98 [(constants.RS_NORMAL, "node2")],
99 [(constants.RS_NORMAL, "node3")]])
100 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node3")),
101 [["node1"], ["node2"], ["node3"]])
103 q = query.Query(fielddef, ["name", "master"])
104 self.assertEqual(q.RequestedData(), set([STATIC]))
105 self.assertEqual(len(q._fields), 2)
106 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
107 [[(constants.RS_NORMAL, "node1"),
108 (constants.RS_NORMAL, False)],
109 [(constants.RS_NORMAL, "node2"),
110 (constants.RS_NORMAL, False)],
111 [(constants.RS_NORMAL, "node3"),
112 (constants.RS_NORMAL, True)],
115 q = query.Query(fielddef, ["name", "master", "disk0.size"])
116 self.assertEqual(q.RequestedData(), set([STATIC, DISK]))
117 self.assertEqual(len(q._fields), 3)
118 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
119 [[(constants.RS_NORMAL, "node1"),
120 (constants.RS_NORMAL, False),
121 (constants.RS_NORMAL, 0)],
122 [(constants.RS_NORMAL, "node2"),
123 (constants.RS_NORMAL, True),
124 (constants.RS_NORMAL, 3)],
125 [(constants.RS_NORMAL, "node3"),
126 (constants.RS_NORMAL, False),
127 (constants.RS_NORMAL, 5)],
130 # With unknown column
131 q = query.Query(fielddef, ["disk2.size", "disk1.size", "disk99.size",
133 self.assertEqual(q.RequestedData(), set([DISK]))
134 self.assertEqual(len(q._fields), 4)
135 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
136 [[(constants.RS_NORMAL, 2),
137 (constants.RS_NORMAL, 1),
138 (constants.RS_UNKNOWN, None),
139 (constants.RS_NORMAL, 0)],
140 [(constants.RS_UNAVAIL, None),
141 (constants.RS_NORMAL, 4),
142 (constants.RS_UNKNOWN, None),
143 (constants.RS_NORMAL, 3)],
144 [(constants.RS_NORMAL, 7),
145 (constants.RS_NORMAL, 6),
146 (constants.RS_UNKNOWN, None),
147 (constants.RS_NORMAL, 5)],
149 self.assertRaises(errors.OpPrereqError, q.OldStyleQuery,
150 _QueryData(data, mastername="node2"))
151 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()], [
152 { "name": "disk2.size", "title": "DiskSize2",
153 "kind": constants.QFT_UNIT, "doc": "Disk size 2", },
154 { "name": "disk1.size", "title": "DiskSize1",
155 "kind": constants.QFT_UNIT, "doc": "Disk size 1", },
156 { "name": "disk99.size", "title": "disk99.size",
157 "kind": constants.QFT_UNKNOWN,
158 "doc": "Unknown field 'disk99.size'", },
159 { "name": "disk0.size", "title": "DiskSize0",
160 "kind": constants.QFT_UNIT, "doc": "Disk size 0", },
164 q = query.Query(fielddef, [])
165 self.assertEqual(q.RequestedData(), set([]))
166 self.assertEqual(len(q._fields), 0)
167 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
169 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node2")),
171 self.assertEqual(q.GetFields(), [])
173 def testPrepareFieldList(self):
175 for (a, b) in [("name", "name"), ("NAME", "name")]:
176 self.assertRaises(AssertionError, query._PrepareFieldList, [
177 (query._MakeField("name", b, constants.QFT_TEXT, "Name"), None, 0,
179 (query._MakeField("other", a, constants.QFT_TEXT, "Other"), None, 0,
183 # Non-lowercase names
184 self.assertRaises(AssertionError, query._PrepareFieldList, [
185 (query._MakeField("NAME", "Name", constants.QFT_TEXT, "Name"), None, 0,
188 self.assertRaises(AssertionError, query._PrepareFieldList, [
189 (query._MakeField("Name", "Name", constants.QFT_TEXT, "Name"), None, 0,
194 self.assertRaises(AssertionError, query._PrepareFieldList, [
195 (query._MakeField("", "Name", constants.QFT_TEXT, "Name"), None, 0,
200 self.assertRaises(AssertionError, query._PrepareFieldList, [
201 (query._MakeField("name", "", constants.QFT_TEXT, "Name"), None, 0,
205 # Whitespace in title
206 self.assertRaises(AssertionError, query._PrepareFieldList, [
207 (query._MakeField("name", "Co lu mn", constants.QFT_TEXT, "Name"),
208 None, 0, lambda *args: None),
211 # No callable function
212 self.assertRaises(AssertionError, query._PrepareFieldList, [
213 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
217 # Invalid documentation
218 for doc in ["", ".", "Hello world\n", "Hello\nWo\nrld", "Hello World!",
219 "HelloWorld.", "only lowercase", ",", " x y z .\t", " "]:
220 self.assertRaises(AssertionError, query._PrepareFieldList, [
221 (query._MakeField("name", "Name", constants.QFT_TEXT, doc),
222 None, 0, lambda *args: None),
225 def testUnknown(self):
226 fielddef = query._PrepareFieldList([
227 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
228 None, 0, lambda _, item: "name%s" % item),
229 (query._MakeField("other0", "Other0", constants.QFT_TIMESTAMP, "Other"),
230 None, 0, lambda *args: 1234),
231 (query._MakeField("nodata", "NoData", constants.QFT_NUMBER, "No data"),
232 None, 0, lambda *args: query._FS_NODATA ),
233 (query._MakeField("unavail", "Unavail", constants.QFT_BOOL, "Unavail"),
234 None, 0, lambda *args: query._FS_UNAVAIL),
237 for selected in [["foo"], ["Hello", "World"],
238 ["name1", "other", "foo"]]:
239 q = query.Query(fielddef, selected)
240 self.assertEqual(len(q._fields), len(selected))
241 self.assert_(compat.all(len(row) == len(selected)
242 for row in q.Query(_QueryData(range(1, 10)))))
243 self.assertEqual(q.Query(_QueryData(range(1, 10))),
244 [[(constants.RS_UNKNOWN, None)] * len(selected)
245 for i in range(1, 10)])
246 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()],
247 [{ "name": name, "title": name,
248 "kind": constants.QFT_UNKNOWN,
249 "doc": "Unknown field '%s'" % name}
250 for name in selected])
252 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail"])
253 self.assertEqual(len(q._fields), 4)
254 self.assertEqual(q.OldStyleQuery(_QueryData(range(1, 10))), [
255 ["name%s" % i, 1234, None, None]
256 for i in range(1, 10)
259 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail", "unk"])
260 self.assertEqual(len(q._fields), 5)
261 self.assertEqual(q.Query(_QueryData(range(1, 10))),
262 [[(constants.RS_NORMAL, "name%s" % i),
263 (constants.RS_NORMAL, 1234),
264 (constants.RS_NODATA, None),
265 (constants.RS_UNAVAIL, None),
266 (constants.RS_UNKNOWN, None)]
267 for i in range(1, 10)])
269 def testAliases(self):
271 (query._MakeField("a", "a-title", constants.QFT_TEXT, "Field A"),
272 None, 0, lambda *args: None),
273 (query._MakeField("b", "b-title", constants.QFT_TEXT, "Field B"),
274 None, 0, lambda *args: None),
277 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
279 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
280 [("c", "b"), ("c", "a")])
282 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
284 fdefs = query._PrepareFieldList(fields, [("c", "b")])
285 self.assertEqual(len(fdefs), 3)
286 self.assertEqual(fdefs["b"][1:], fdefs["c"][1:])
289 class TestGetNodeRole(unittest.TestCase):
294 (constants.NR_MASTER, "node1", objects.Node(name="node1")),
295 (constants.NR_MCANDIDATE, "master",
296 objects.Node(name="node1", master_candidate=True)),
297 (constants.NR_REGULAR, "master", objects.Node(name="node1")),
298 (constants.NR_DRAINED, "master",
299 objects.Node(name="node1", drained=True)),
300 (constants.NR_OFFLINE,
301 "master", objects.Node(name="node1", offline=True)),
304 for (role, master_name, node) in checks:
305 result = query._GetNodeRole(node, master_name)
306 self.assertEqual(result, role)
307 tested_role.add(result)
309 self.assertEqual(tested_role, constants.NR_ALL)
312 class TestNodeQuery(unittest.TestCase):
313 def _Create(self, selected):
314 return query.Query(query.NODE_FIELDS, selected)
316 def testSimple(self):
318 objects.Node(name="node1", drained=False),
319 objects.Node(name="node2", drained=True),
320 objects.Node(name="node3", drained=False),
322 for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]:
323 nqd = query.NodeQueryData(nodes, live_data, None, None, None, None, None,
326 q = self._Create(["name", "drained"])
327 self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG]))
328 self.assertEqual(q.Query(nqd),
329 [[(constants.RS_NORMAL, "node1"),
330 (constants.RS_NORMAL, False)],
331 [(constants.RS_NORMAL, "node2"),
332 (constants.RS_NORMAL, True)],
333 [(constants.RS_NORMAL, "node3"),
334 (constants.RS_NORMAL, False)],
336 self.assertEqual(q.OldStyleQuery(nqd),
342 selected = query.NODE_FIELDS.keys()
343 field_index = dict((field, idx) for idx, field in enumerate(selected))
345 q = self._Create(selected)
346 self.assertEqual(q.RequestedData(),
347 set([query.NQ_CONFIG, query.NQ_LIVE, query.NQ_INST,
348 query.NQ_GROUP, query.NQ_OOB]))
350 cluster = objects.Cluster(cluster_name="testcluster",
351 hvparams=constants.HVC_DEFAULTS,
353 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
356 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
358 ndparams=constants.NDC_DEFAULTS,
361 node_names = ["node%s" % i for i in range(20)]
362 master_name = node_names[3]
364 objects.Node(name=name,
365 primary_ip="192.0.2.%s" % idx,
366 secondary_ip="192.0.100.%s" % idx,
367 serial_no=7789 * idx,
368 master_candidate=(name != master_name and idx % 3 == 0),
373 master_capable=False,
378 uuid="fd9ccebe-6339-43c9-a82e-94bbe575%04d" % idx)
379 for idx, name in enumerate(node_names)
382 master_node = nodes[3]
383 master_node.AddTag("masternode")
384 master_node.AddTag("another")
385 master_node.AddTag("tag")
386 master_node.ctime = None
387 master_node.mtime = None
388 assert master_node.name == master_name
390 live_data_name = node_names[4]
391 assert live_data_name != master_name
394 "bootid": "a2504766-498e-4b25-b21e-d23098dc3af4",
401 "dfree": 5 * 1024 * 1024,
402 "dtotal": 100 * 1024 * 1024,
405 assert (sorted(query._NODE_LIVE_FIELDS.keys()) ==
406 sorted(fake_live_data.keys()))
408 live_data = dict.fromkeys(node_names, {})
409 live_data[live_data_name] = \
410 dict((query._NODE_LIVE_FIELDS[name][2], value)
411 for name, value in fake_live_data.items())
413 node_to_primary = dict((name, set()) for name in node_names)
414 node_to_primary[master_name].update(["inst1", "inst2"])
416 node_to_secondary = dict((name, set()) for name in node_names)
417 node_to_secondary[live_data_name].update(["instX", "instY", "instZ"])
419 ng_uuid = "492b4b74-8670-478a-b98d-4c53a76238e6"
421 ng_uuid: objects.NodeGroup(name="ng1", uuid=ng_uuid, ndparams={}),
424 oob_not_powered_node = node_names[0]
425 nodes[0].powered = False
426 oob_support = dict((name, False) for name in node_names)
427 oob_support[master_name] = True
428 oob_support[oob_not_powered_node] = True
430 master_node.group = ng_uuid
432 nqd = query.NodeQueryData(nodes, live_data, master_name,
433 node_to_primary, node_to_secondary, groups,
434 oob_support, cluster)
435 result = q.Query(nqd)
436 self.assert_(compat.all(len(row) == len(selected) for row in result))
437 self.assertEqual([row[field_index["name"]] for row in result],
438 [(constants.RS_NORMAL, name) for name in node_names])
440 node_to_row = dict((row[field_index["name"]][1], idx)
441 for idx, row in enumerate(result))
443 master_row = result[node_to_row[master_name]]
444 self.assert_(master_row[field_index["master"]])
445 self.assert_(master_row[field_index["role"]], "M")
446 self.assertEqual(master_row[field_index["group"]],
447 (constants.RS_NORMAL, "ng1"))
448 self.assertEqual(master_row[field_index["group.uuid"]],
449 (constants.RS_NORMAL, ng_uuid))
450 self.assertEqual(master_row[field_index["ctime"]],
451 (constants.RS_UNAVAIL, None))
452 self.assertEqual(master_row[field_index["mtime"]],
453 (constants.RS_UNAVAIL, None))
455 self.assert_(row[field_index["pip"]] == node.primary_ip and
456 row[field_index["sip"]] == node.secondary_ip and
457 set(row[field_index["tags"]]) == node.GetTags() and
458 row[field_index["serial_no"]] == node.serial_no and
459 row[field_index["role"]] == query._GetNodeRole(node,
461 (node.name == master_name or
462 (row[field_index["group"]] == "<unknown>" and
463 row[field_index["group.uuid"]] is None and
464 row[field_index["ctime"]] == (constants.RS_NORMAL,
466 row[field_index["mtime"]] == (constants.RS_NORMAL,
468 row[field_index["powered"]] == (constants.RS_NORMAL,
470 (node.name == oob_not_powered_node and
471 row[field_index["powered"]] == (constants.RS_NORMAL,
473 row[field_index["powered"]] == (constants.RS_UNAVAIL, None)
474 for row, node in zip(result, nodes))
476 live_data_row = result[node_to_row[live_data_name]]
478 for (field, value) in fake_live_data.items():
479 self.assertEqual(live_data_row[field_index[field]],
480 (constants.RS_NORMAL, value))
482 self.assertEqual(master_row[field_index["pinst_cnt"]],
483 (constants.RS_NORMAL, 2))
484 self.assertEqual(live_data_row[field_index["sinst_cnt"]],
485 (constants.RS_NORMAL, 3))
486 self.assertEqual(master_row[field_index["pinst_list"]],
487 (constants.RS_NORMAL,
488 list(node_to_primary[master_name])))
489 self.assertEqual(live_data_row[field_index["sinst_list"]],
490 (constants.RS_NORMAL,
491 list(node_to_secondary[live_data_name])))
493 def testGetLiveNodeField(self):
495 objects.Node(name="node1", drained=False, offline=False,
497 objects.Node(name="node2", drained=True, offline=False,
499 objects.Node(name="node3", drained=False, offline=False,
501 objects.Node(name="node4", drained=False, offline=True,
503 objects.Node(name="node5", drained=False, offline=False,
506 live_data = dict.fromkeys([node.name for node in nodes], {})
509 nqd = query.NodeQueryData(None, None, None, None, None, None, None, None)
510 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
515 ctx = _QueryData(None, curlive_data={
519 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
523 # Wrong format/datatype
524 ctx = _QueryData(None, curlive_data={
525 "hello": ["Hello World"],
528 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
533 assert nodes[3].offline
534 ctx = _QueryData(None, curlive_data={})
535 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
537 query._FS_OFFLINE, None)
540 ctx = _QueryData(None, curlive_data={"hello": 123})
541 self.assertRaises(AssertionError, query._GetLiveNodeField,
542 "hello", constants.QFT_BOOL, ctx, nodes[0])
544 # Non-vm_capable node
545 assert not nodes[4].vm_capable
546 ctx = _QueryData(None, curlive_data={})
547 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
549 query._FS_UNAVAIL, None)
552 class TestInstanceQuery(unittest.TestCase):
553 def _Create(self, selected):
554 return query.Query(query.INSTANCE_FIELDS, selected)
556 def testSimple(self):
557 q = self._Create(["name", "be/memory", "ip"])
558 self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
560 cluster = objects.Cluster(cluster_name="testcluster",
561 hvparams=constants.HVC_DEFAULTS,
563 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
566 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
572 objects.Instance(name="inst1", hvparams={}, beparams={}, osparams={},
574 objects.Instance(name="inst2", hvparams={}, nics=[], osparams={},
577 constants.BE_MEMORY: 512,
579 objects.Instance(name="inst3", hvparams={}, beparams={}, osparams={},
580 os="dos", nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
583 iqd = query.InstanceQueryData(instances, cluster, None, [], [], {},
584 set(), {}, None, None)
585 self.assertEqual(q.Query(iqd),
586 [[(constants.RS_NORMAL, "inst1"),
587 (constants.RS_NORMAL, 128),
588 (constants.RS_UNAVAIL, None),
590 [(constants.RS_NORMAL, "inst2"),
591 (constants.RS_NORMAL, 512),
592 (constants.RS_UNAVAIL, None),
594 [(constants.RS_NORMAL, "inst3"),
595 (constants.RS_NORMAL, 128),
596 (constants.RS_NORMAL, "192.0.2.99"),
598 self.assertEqual(q.OldStyleQuery(iqd),
599 [["inst1", 128, None],
600 ["inst2", 512, None],
601 ["inst3", 128, "192.0.2.99"]])
604 selected = query.INSTANCE_FIELDS.keys()
605 fieldidx = dict((field, idx) for idx, field in enumerate(selected))
607 macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
610 q = self._Create(selected)
611 self.assertEqual(q.RequestedData(),
612 set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE,
613 query.IQ_CONSOLE, query.IQ_NODES]))
615 cluster = objects.Cluster(cluster_name="testcluster",
616 hvparams=constants.HVC_DEFAULTS,
618 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
621 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
624 tcpudp_port_pool=set(),
627 "clean_install": "yes",
631 offline_nodes = ["nodeoff1", "nodeoff2"]
632 bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
633 nodes = ["node%s" % i for i in range(10)] + bad_nodes
636 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
637 uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
638 ctime=1291244000, mtime=1291244400, serial_no=30,
639 admin_up=True, hypervisor=constants.HT_XEN_PVM, os="linux1",
640 primary_node="node1",
641 disk_template=constants.DT_PLAIN,
644 objects.Instance(name="inst2", hvparams={}, nics=[],
645 uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
646 ctime=1291211000, mtime=1291211077, serial_no=1,
647 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
648 primary_node="node5",
649 disk_template=constants.DT_DISKLESS,
652 constants.BE_MEMORY: 512,
655 objects.Instance(name="inst3", hvparams={}, beparams={},
656 uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
657 ctime=1291011000, mtime=1291013000, serial_no=1923,
658 admin_up=False, hypervisor=constants.HT_KVM, os="busybox",
659 primary_node="node6",
660 disk_template=constants.DT_DRBD8,
663 objects.NIC(ip="192.0.2.99", mac=macs.pop(),
665 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
667 objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
670 objects.Instance(name="inst4", hvparams={}, beparams={},
671 uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
672 ctime=1291244390, mtime=1291244395, serial_no=25,
673 admin_up=False, hypervisor=constants.HT_XEN_PVM, os="linux1",
674 primary_node="nodeoff2",
675 disk_template=constants.DT_DRBD8,
678 objects.NIC(ip="192.0.2.1", mac=macs.pop(),
680 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
682 objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
683 objects.NIC(ip="192.0.2.3", mac=macs.pop(),
685 constants.NIC_MODE: constants.NIC_MODE_ROUTED,
687 objects.NIC(ip="192.0.2.4", mac=macs.pop(),
689 constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
690 constants.NIC_LINK: "eth123",
694 objects.Instance(name="inst5", hvparams={}, nics=[],
695 uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
696 ctime=1231211000, mtime=1261200000, serial_no=3,
697 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
698 primary_node="nodebad2",
699 disk_template=constants.DT_DISKLESS,
702 constants.BE_MEMORY: 512,
705 objects.Instance(name="inst6", hvparams={}, nics=[],
706 uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
707 ctime=7513, mtime=11501, serial_no=13390,
708 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
709 primary_node="node7",
710 disk_template=constants.DT_DISKLESS,
713 constants.BE_MEMORY: 768,
716 "clean_install": "no",
718 objects.Instance(name="inst7", hvparams={}, nics=[],
719 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
720 ctime=None, mtime=None, serial_no=1947,
721 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
722 primary_node="node6",
723 disk_template=constants.DT_DISKLESS,
729 assert not utils.FindDuplicates(inst.name for inst in instances)
731 instbyname = dict((inst.name, inst) for inst in instances)
733 disk_usage = dict((inst.name,
734 cmdlib._ComputeDiskSize(inst.disk_template,
736 for disk in inst.disks]))
737 for inst in instances)
740 "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
741 "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
759 wrongnode_inst = set(["inst7"])
761 consinfo = dict((inst.name, None) for inst in instances)
762 consinfo["inst7"] = \
763 objects.InstanceConsole(instance="inst7", kind=constants.CONS_SSH,
764 host=instbyname["inst7"].primary_node,
765 user=constants.GANETI_RUNAS,
766 command=["hostname"]).ToDict()
768 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
769 offline_nodes, bad_nodes, live_data,
770 wrongnode_inst, consinfo, {}, {})
771 result = q.Query(iqd)
772 self.assertEqual(len(result), len(instances))
773 self.assert_(compat.all(len(row) == len(selected)
776 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
777 "Offline nodes not included in bad nodes"
779 tested_status = set()
781 for (inst, row) in zip(instances, result):
782 assert inst.primary_node in nodes
784 self.assertEqual(row[fieldidx["name"]],
785 (constants.RS_NORMAL, inst.name))
787 if inst.primary_node in offline_nodes:
788 exp_status = constants.INSTST_NODEOFFLINE
789 elif inst.primary_node in bad_nodes:
790 exp_status = constants.INSTST_NODEDOWN
791 elif inst.name in live_data:
792 if inst.name in wrongnode_inst:
793 exp_status = constants.INSTST_WRONGNODE
795 exp_status = constants.INSTST_RUNNING
797 exp_status = constants.INSTST_ERRORUP
799 exp_status = constants.INSTST_ERRORDOWN
801 exp_status = constants.INSTST_ADMINDOWN
803 self.assertEqual(row[fieldidx["status"]],
804 (constants.RS_NORMAL, exp_status))
806 (_, status) = row[fieldidx["status"]]
807 tested_status.add(status)
809 for (field, livefield) in [("oper_ram", "memory"),
810 ("oper_vcpus", "vcpus")]:
811 if inst.primary_node in bad_nodes:
812 exp = (constants.RS_NODATA, None)
813 elif inst.name in live_data:
814 value = live_data[inst.name].get(livefield, None)
816 exp = (constants.RS_UNAVAIL, None)
818 exp = (constants.RS_NORMAL, value)
820 exp = (constants.RS_UNAVAIL, None)
822 self.assertEqual(row[fieldidx[field]], exp)
824 bridges = inst_bridges.get(inst.name, [])
825 self.assertEqual(row[fieldidx["nic.bridges"]],
826 (constants.RS_NORMAL, bridges))
828 self.assertEqual(row[fieldidx["bridge"]],
829 (constants.RS_NORMAL, bridges[0]))
831 self.assertEqual(row[fieldidx["bridge"]],
832 (constants.RS_UNAVAIL, None))
834 for i in range(constants.MAX_NICS):
835 if i < len(bridges) and bridges[i] is not None:
836 exp = (constants.RS_NORMAL, bridges[i])
838 exp = (constants.RS_UNAVAIL, None)
839 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
841 if inst.primary_node in bad_nodes:
842 exp = (constants.RS_NODATA, None)
844 exp = (constants.RS_NORMAL, inst.name in live_data)
845 self.assertEqual(row[fieldidx["oper_state"]], exp)
847 cust_exp = (constants.RS_NORMAL, {})
848 if inst.os == "deb99":
849 if inst.name == "inst6":
850 exp = (constants.RS_NORMAL, {"clean_install": "no"})
853 exp = (constants.RS_NORMAL, {"clean_install": "yes"})
855 exp = (constants.RS_NORMAL, {})
856 self.assertEqual(row[fieldidx["osparams"]], exp)
857 self.assertEqual(row[fieldidx["custom_osparams"]], cust_exp)
859 usage = disk_usage[inst.name]
862 self.assertEqual(row[fieldidx["disk_usage"]],
863 (constants.RS_NORMAL, usage))
865 for alias, target in [("sda_size", "disk.size/0"),
866 ("sdb_size", "disk.size/1"),
867 ("vcpus", "be/vcpus"),
869 ("mac", "nic.mac/0"),
870 ("bridge", "nic.bridge/0"),
871 ("nic_mode", "nic.mode/0"),
872 ("nic_link", "nic.link/0"),
874 self.assertEqual(row[fieldidx[alias]], row[fieldidx[target]])
876 for field in ["ctime", "mtime"]:
877 if getattr(inst, field) is None:
879 exp = (constants.RS_UNAVAIL, None)
881 exp = (constants.RS_NORMAL, getattr(inst, field))
882 self.assertEqual(row[fieldidx[field]], exp)
884 self._CheckInstanceConsole(inst, row[fieldidx["console"]])
886 # Ensure all possible status' have been tested
887 self.assertEqual(tested_status, constants.INSTST_ALL)
889 def _CheckInstanceConsole(self, instance, (status, consdata)):
890 if instance.name == "inst7":
891 self.assertEqual(status, constants.RS_NORMAL)
892 console = objects.InstanceConsole.FromDict(consdata)
893 self.assertTrue(console.Validate())
894 self.assertEqual(console.host, instance.primary_node)
896 self.assertEqual(status, constants.RS_UNAVAIL)
899 class TestGroupQuery(unittest.TestCase):
903 objects.NodeGroup(name="default",
904 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
905 alloc_policy=constants.ALLOC_POLICY_PREFERRED),
906 objects.NodeGroup(name="restricted",
907 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
908 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
911 def _Create(self, selected):
912 return query.Query(query.GROUP_FIELDS, selected)
914 def testSimple(self):
915 q = self._Create(["name", "uuid", "alloc_policy"])
916 gqd = query.GroupQueryData(self.groups, None, None)
918 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
920 self.assertEqual(q.Query(gqd),
921 [[(constants.RS_NORMAL, "default"),
922 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
923 (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
925 [(constants.RS_NORMAL, "restricted"),
926 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
927 (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
933 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
934 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
937 q = self._Create(["name", "node_cnt", "node_list"])
938 gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
940 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
942 self.assertEqual(q.Query(gqd),
943 [[(constants.RS_NORMAL, "default"),
944 (constants.RS_NORMAL, 2),
945 (constants.RS_NORMAL, ["node1", "node2"]),
947 [(constants.RS_NORMAL, "restricted"),
948 (constants.RS_NORMAL, 3),
949 (constants.RS_NORMAL, ["node1", "node9", "node10"]),
953 def testInstances(self):
954 groups_to_instances = {
955 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
956 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
959 q = self._Create(["pinst_cnt", "pinst_list"])
960 gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
962 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
964 self.assertEqual(q.Query(gqd),
965 [[(constants.RS_NORMAL, 2),
966 (constants.RS_NORMAL, ["inst1", "inst2"]),
968 [(constants.RS_NORMAL, 3),
969 (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
974 class TestOsQuery(unittest.TestCase):
975 def _Create(self, selected):
976 return query.Query(query.OS_FIELDS, selected)
979 variants = ["v00", "plain", "v3", "var0", "v33", "v20"]
980 api_versions = [10, 0, 15, 5]
981 parameters = ["zpar3", "apar9"]
983 assert variants != sorted(variants) and variants != utils.NiceSort(variants)
984 assert (api_versions != sorted(api_versions) and
985 api_versions != utils.NiceSort(variants))
986 assert (parameters != sorted(parameters) and
987 parameters != utils.NiceSort(parameters))
990 query.OsInfo(name="debian", valid=False, hidden=False, blacklisted=False,
991 variants=set(), api_versions=set(), parameters=set(),
992 node_status={ "some": "status", }),
993 query.OsInfo(name="dos", valid=True, hidden=False, blacklisted=True,
994 variants=set(variants),
995 api_versions=set(api_versions),
996 parameters=set(parameters),
997 node_status={ "some": "other", "status": None, }),
1001 q = self._Create(["name", "valid", "hidden", "blacklisted", "variants",
1002 "api_versions", "parameters", "node_status"])
1003 self.assertEqual(q.RequestedData(), set([]))
1004 self.assertEqual(q.Query(data),
1005 [[(constants.RS_NORMAL, "debian"),
1006 (constants.RS_NORMAL, False),
1007 (constants.RS_NORMAL, False),
1008 (constants.RS_NORMAL, False),
1009 (constants.RS_NORMAL, []),
1010 (constants.RS_NORMAL, []),
1011 (constants.RS_NORMAL, []),
1012 (constants.RS_NORMAL, {"some": "status"})],
1013 [(constants.RS_NORMAL, "dos"),
1014 (constants.RS_NORMAL, True),
1015 (constants.RS_NORMAL, False),
1016 (constants.RS_NORMAL, True),
1017 (constants.RS_NORMAL,
1018 ["plain", "v00", "v3", "v20", "v33", "var0"]),
1019 (constants.RS_NORMAL, [0, 5, 10, 15]),
1020 (constants.RS_NORMAL, ["apar9", "zpar3"]),
1021 (constants.RS_NORMAL,
1022 { "some": "other", "status": None, })
1026 class TestQueryFields(unittest.TestCase):
1027 def testAllFields(self):
1028 for fielddefs in query.ALL_FIELD_LISTS:
1029 result = query.QueryFields(fielddefs, None)
1030 self.assert_(isinstance(result, dict))
1031 response = objects.QueryFieldsResponse.FromDict(result)
1032 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1033 [(fdef2.name, fdef2.title)
1034 for (fdef2, _, _, _) in utils.NiceSort(fielddefs.values(),
1035 key=lambda x: x[0].name)])
1037 def testSomeFields(self):
1038 rnd = random.Random(5357)
1041 for fielddefs in query.ALL_FIELD_LISTS:
1042 if len(fielddefs) > 20:
1043 sample_size = rnd.randint(5, 20)
1045 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
1046 fields = [fdef for (fdef, _, _, _) in rnd.sample(fielddefs.values(),
1048 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
1049 self.assert_(isinstance(result, dict))
1050 response = objects.QueryFieldsResponse.FromDict(result)
1051 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
1052 [(fdef2.name, fdef2.title) for fdef2 in fields])
1055 class TestQueryFilter(unittest.TestCase):
1056 def testRequestedNames(self):
1057 innerfilter = [["=", "name", "x%s" % i] for i in range(4)]
1059 for fielddefs in query.ALL_FIELD_LISTS:
1060 assert "name" in fielddefs
1063 q = query.Query(fielddefs, ["name"], filter_=["=", "name", "abc"],
1065 self.assertEqual(q.RequestedNames(), None)
1068 q = query.Query(fielddefs, ["name"], filter_=None, namefield="name")
1069 self.assertEqual(q.RequestedNames(), None)
1072 q = query.Query(fielddefs, ["name"], filter_=["|"], namefield="name")
1073 self.assertEqual(q.RequestedNames(), None)
1076 q = query.Query(fielddefs, ["name"], filter_=["|"] + innerfilter,
1078 self.assertEqual(q.RequestedNames(), ["x0", "x1", "x2", "x3"])
1080 # Check reverse order
1081 q = query.Query(fielddefs, ["name"],
1082 filter_=["|"] + list(reversed(innerfilter)),
1084 self.assertEqual(q.RequestedNames(), ["x3", "x2", "x1", "x0"])
1087 q = query.Query(fielddefs, ["name"],
1088 filter_=["|"] + innerfilter + list(reversed(innerfilter)),
1090 self.assertEqual(q.RequestedNames(), ["x0", "x1", "x2", "x3"])
1092 # Unknown name field
1093 self.assertRaises(AssertionError, query.Query, fielddefs, ["name"],
1094 namefield="_unknown_field_")
1097 q = query.Query(fielddefs, ["name"],
1098 filter_=["|", ["=", "name", "foo"],
1099 ["&", ["=", "name", ""]]],
1101 self.assertTrue(q.RequestedNames() is None)
1104 q = query.Query(fielddefs, ["name"],
1105 filter_=["|", ["=", "name", "foo"],
1106 ["!", ["=", "name", ""]]],
1108 self.assertTrue(q.RequestedNames() is None)
1110 # Filter with only OR (names must be in correct order)
1111 q = query.Query(fielddefs, ["name"],
1112 filter_=["|", ["=", "name", "x17361"],
1113 ["|", ["=", "name", "x22015"]],
1114 ["|", ["|", ["=", "name", "x13193"]]],
1115 ["=", "name", "x15215"]],
1117 self.assertEqual(q.RequestedNames(),
1118 ["x17361", "x22015", "x13193", "x15215"])
1121 def _GenNestedFilter(op, depth):
1122 nested = ["=", "name", "value"]
1123 for i in range(depth):
1124 nested = [op, nested]
1127 def testCompileFilter(self):
1128 levels_max = query._FilterCompilerHelper._LEVELS_MAX
1131 [], ["="], ["=", "foo"], ["unknownop"], ["!"],
1132 ["=", "_unknown_field", "value"],
1133 self._GenNestedFilter("|", levels_max),
1134 self._GenNestedFilter("|", levels_max * 3),
1135 self._GenNestedFilter("!", levels_max),
1138 for fielddefs in query.ALL_FIELD_LISTS:
1139 for filter_ in checks:
1140 self.assertRaises(errors.ParameterError, query._CompileFilter,
1141 fielddefs, None, filter_)
1143 for op in ["|", "!"]:
1144 filter_ = self._GenNestedFilter(op, levels_max - 1)
1145 self.assertTrue(callable(query._CompileFilter(fielddefs, None,
1148 def testQueryInputOrder(self):
1149 fielddefs = query._PrepareFieldList([
1150 (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1151 None, 0, lambda ctx, item: item["pnode"]),
1152 (query._MakeField("snode", "SNode", constants.QFT_TEXT, "Secondary"),
1153 None, 0, lambda ctx, item: item["snode"]),
1157 { "pnode": "node1", "snode": "node44", },
1158 { "pnode": "node30", "snode": "node90", },
1159 { "pnode": "node25", "snode": "node1", },
1160 { "pnode": "node20", "snode": "node1", },
1163 filter_ = ["|", ["=", "pnode", "node1"], ["=", "snode", "node1"]]
1165 q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode",
1167 self.assertTrue(q.RequestedNames() is None)
1168 self.assertFalse(q.RequestedData())
1169 self.assertEqual(q.Query(data),
1170 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1171 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1172 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1174 # Try again with reversed input data
1175 self.assertEqual(q.Query(reversed(data)),
1176 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1177 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1178 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")]])
1180 # No name field, result must be in incoming order
1181 q = query.Query(fielddefs, ["pnode", "snode"], namefield=None,
1183 self.assertFalse(q.RequestedData())
1184 self.assertEqual(q.Query(data),
1185 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1186 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1187 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1188 self.assertEqual(q.OldStyleQuery(data), [
1189 ["node1", "node44"],
1190 ["node25", "node1"],
1191 ["node20", "node1"],
1193 self.assertEqual(q.Query(reversed(data)),
1194 [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1195 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1196 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1197 self.assertEqual(q.OldStyleQuery(reversed(data)), [
1198 ["node20", "node1"],
1199 ["node25", "node1"],
1200 ["node1", "node44"],
1203 # Name field, but no sorting, result must be in incoming order
1204 q = query.Query(fielddefs, ["pnode", "snode"], namefield="pnode")
1205 self.assertFalse(q.RequestedData())
1206 self.assertEqual(q.Query(data, sort_by_name=False),
1207 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")],
1208 [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1209 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1210 [(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")]])
1211 self.assertEqual(q.OldStyleQuery(data, sort_by_name=False), [
1212 ["node1", "node44"],
1213 ["node30", "node90"],
1214 ["node25", "node1"],
1215 ["node20", "node1"],
1217 self.assertEqual(q.Query(reversed(data), sort_by_name=False),
1218 [[(constants.RS_NORMAL, "node20"), (constants.RS_NORMAL, "node1")],
1219 [(constants.RS_NORMAL, "node25"), (constants.RS_NORMAL, "node1")],
1220 [(constants.RS_NORMAL, "node30"), (constants.RS_NORMAL, "node90")],
1221 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "node44")]])
1222 self.assertEqual(q.OldStyleQuery(reversed(data), sort_by_name=False), [
1223 ["node20", "node1"],
1224 ["node25", "node1"],
1225 ["node30", "node90"],
1226 ["node1", "node44"],
1229 def testEqualNamesOrder(self):
1230 fielddefs = query._PrepareFieldList([
1231 (query._MakeField("pnode", "PNode", constants.QFT_TEXT, "Primary"),
1232 None, 0, lambda ctx, item: item["pnode"]),
1233 (query._MakeField("num", "Num", constants.QFT_NUMBER, "Num"),
1234 None, 0, lambda ctx, item: item["num"]),
1238 { "pnode": "node1", "num": 100, },
1239 { "pnode": "node1", "num": 25, },
1240 { "pnode": "node2", "num": 90, },
1241 { "pnode": "node2", "num": 30, },
1244 q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1245 filter_=["|", ["=", "pnode", "node1"],
1246 ["=", "pnode", "node2"],
1247 ["=", "pnode", "node1"]])
1248 self.assertEqual(q.RequestedNames(), ["node1", "node2"],
1249 msg="Did not return unique names")
1250 self.assertFalse(q.RequestedData())
1251 self.assertEqual(q.Query(data),
1252 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1253 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1254 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1255 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1256 self.assertEqual(q.Query(data, sort_by_name=False),
1257 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 100)],
1258 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, 25)],
1259 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 90)],
1260 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, 30)]])
1263 { "pnode": "nodeX", "num": 50, },
1264 { "pnode": "nodeY", "num": 40, },
1265 { "pnode": "nodeX", "num": 30, },
1266 { "pnode": "nodeX", "num": 20, },
1267 { "pnode": "nodeM", "num": 10, },
1270 q = query.Query(fielddefs, ["pnode", "num"], namefield="pnode",
1271 filter_=["|", ["=", "pnode", "nodeX"],
1272 ["=", "pnode", "nodeY"],
1273 ["=", "pnode", "nodeY"],
1274 ["=", "pnode", "nodeY"],
1275 ["=", "pnode", "nodeM"]])
1276 self.assertEqual(q.RequestedNames(), ["nodeX", "nodeY", "nodeM"],
1277 msg="Did not return unique names")
1278 self.assertFalse(q.RequestedData())
1280 # First sorted by name, then input order
1281 self.assertEqual(q.Query(data, sort_by_name=True),
1282 [[(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)],
1283 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1284 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1285 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1286 [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)]])
1289 self.assertEqual(q.Query(data, sort_by_name=False),
1290 [[(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 50)],
1291 [(constants.RS_NORMAL, "nodeY"), (constants.RS_NORMAL, 40)],
1292 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 30)],
1293 [(constants.RS_NORMAL, "nodeX"), (constants.RS_NORMAL, 20)],
1294 [(constants.RS_NORMAL, "nodeM"), (constants.RS_NORMAL, 10)]])
1296 def testFilter(self):
1297 (DK_A, DK_B) = range(1000, 1002)
1299 fielddefs = query._PrepareFieldList([
1300 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1301 DK_A, 0, lambda ctx, item: item["name"]),
1302 (query._MakeField("other", "Other", constants.QFT_TEXT, "Other"),
1303 DK_B, 0, lambda ctx, item: item["other"]),
1307 { "name": "node1", "other": "foo", },
1308 { "name": "node2", "other": "bar", },
1309 { "name": "node3", "other": "Hello", },
1313 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1315 self.assertTrue(q.RequestedNames() is None)
1316 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1317 self.assertEqual(q.Query(data), [])
1320 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1321 filter_=["=", "name", "node1"])
1322 self.assertEqual(q.RequestedNames(), ["node1"])
1323 self.assertEqual(q.Query(data),
1324 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")]])
1326 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1327 filter_=(["|", ["=", "name", "node1"],
1328 ["=", "name", "node3"]]))
1329 self.assertEqual(q.RequestedNames(), ["node1", "node3"])
1330 self.assertEqual(q.Query(data),
1331 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1332 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1335 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1336 filter_=(["|", ["=", "name", "node1"],
1337 ["|", ["=", "name", "node3"],
1338 ["=", "name", "node2"]],
1339 ["=", "name", "node3"]]))
1340 self.assertEqual(q.RequestedNames(), ["node1", "node3", "node2"])
1341 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1342 self.assertEqual(q.Query(data),
1343 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1344 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")],
1345 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, "Hello")]])
1347 # Filter data type mismatch
1348 for i in [-1, 0, 1, 123, [], None, True, False]:
1349 self.assertRaises(errors.ParameterError, query.Query,
1350 fielddefs, ["name", "other"], namefield="name",
1351 filter_=["=", "name", i])
1354 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1355 filter_=["!", ["|", ["=", "name", "node1"],
1356 ["=", "name", "node3"]]])
1357 self.assertTrue(q.RequestedNames() is None)
1358 self.assertEqual(q.Query(data),
1359 [[(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1362 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1363 filter_=["!=", "name", "node3"])
1364 self.assertTrue(q.RequestedNames() is None)
1365 self.assertEqual(q.Query(data),
1366 [[(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, "foo")],
1367 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, "bar")]])
1370 q = query.Query(fielddefs, [], namefield="name",
1371 filter_=["|", ["=", "other", "bar"],
1372 ["=", "name", "foo"]])
1373 self.assertTrue(q.RequestedNames() is None)
1374 self.assertEqual(q.RequestedData(), set([DK_A, DK_B]))
1375 self.assertEqual(q.Query(data), [[]])
1377 # Only one data type
1378 q = query.Query(fielddefs, ["other"], namefield="name",
1379 filter_=["=", "other", "bar"])
1380 self.assertTrue(q.RequestedNames() is None)
1381 self.assertEqual(q.RequestedData(), set([DK_B]))
1382 self.assertEqual(q.Query(data), [[(constants.RS_NORMAL, "bar")]])
1384 q = query.Query(fielddefs, [], namefield="name",
1385 filter_=["=", "other", "bar"])
1386 self.assertTrue(q.RequestedNames() is None)
1387 self.assertEqual(q.RequestedData(), set([DK_B]))
1388 self.assertEqual(q.Query(data), [[]])
1390 def testFilterContains(self):
1391 fielddefs = query._PrepareFieldList([
1392 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1393 None, 0, lambda ctx, item: item["name"]),
1394 (query._MakeField("other", "Other", constants.QFT_OTHER, "Other"),
1395 None, 0, lambda ctx, item: item["other"]),
1399 { "name": "node2", "other": ["x", "y", "bar"], },
1400 { "name": "node3", "other": "Hello", },
1401 { "name": "node1", "other": ["a", "b", "foo"], },
1402 { "name": "empty", "other": []},
1405 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1406 filter_=["=[]", "other", "bar"])
1407 self.assertTrue(q.RequestedNames() is None)
1408 self.assertEqual(q.Query(data), [
1409 [(constants.RS_NORMAL, "node2"),
1410 (constants.RS_NORMAL, ["x", "y", "bar"])],
1413 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1414 filter_=["|", ["=[]", "other", "bar"],
1415 ["=[]", "other", "a"],
1416 ["=[]", "other", "b"]])
1417 self.assertTrue(q.RequestedNames() is None)
1418 self.assertEqual(q.Query(data), [
1419 [(constants.RS_NORMAL, "node1"),
1420 (constants.RS_NORMAL, ["a", "b", "foo"])],
1421 [(constants.RS_NORMAL, "node2"),
1422 (constants.RS_NORMAL, ["x", "y", "bar"])],
1424 self.assertEqual(q.OldStyleQuery(data), [
1425 ["node1", ["a", "b", "foo"]],
1426 ["node2", ["x", "y", "bar"]],
1430 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1431 filter_=["?", "other"])
1432 self.assertEqual(q.OldStyleQuery(data), [
1433 ["node1", ["a", "b", "foo"]],
1434 ["node2", ["x", "y", "bar"]],
1438 q = query.Query(fielddefs, ["name", "other"], namefield="name",
1439 filter_=["!", ["?", "other"]])
1440 self.assertEqual(q.OldStyleQuery(data), [
1444 def testFilterHostname(self):
1445 fielddefs = query._PrepareFieldList([
1446 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1447 None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1451 { "name": "node1.example.com", },
1452 { "name": "node2.example.com", },
1453 { "name": "node2.example.net", },
1456 q = query.Query(fielddefs, ["name"], namefield="name",
1457 filter_=["=", "name", "node2"])
1458 self.assertEqual(q.RequestedNames(), ["node2"])
1459 self.assertEqual(q.Query(data), [
1460 [(constants.RS_NORMAL, "node2.example.com")],
1461 [(constants.RS_NORMAL, "node2.example.net")],
1464 q = query.Query(fielddefs, ["name"], namefield="name",
1465 filter_=["=", "name", "node1"])
1466 self.assertEqual(q.RequestedNames(), ["node1"])
1467 self.assertEqual(q.Query(data), [
1468 [(constants.RS_NORMAL, "node1.example.com")],
1471 q = query.Query(fielddefs, ["name"], namefield="name",
1472 filter_=["=", "name", "othername"])
1473 self.assertEqual(q.RequestedNames(), ["othername"])
1474 self.assertEqual(q.Query(data), [])
1476 q = query.Query(fielddefs, ["name"], namefield="name",
1477 filter_=["|", ["=", "name", "node1.example.com"],
1478 ["=", "name", "node2"]])
1479 self.assertEqual(q.RequestedNames(), ["node1.example.com", "node2"])
1480 self.assertEqual(q.Query(data), [
1481 [(constants.RS_NORMAL, "node1.example.com")],
1482 [(constants.RS_NORMAL, "node2.example.com")],
1483 [(constants.RS_NORMAL, "node2.example.net")],
1485 self.assertEqual(q.OldStyleQuery(data), [
1486 ["node1.example.com"],
1487 ["node2.example.com"],
1488 ["node2.example.net"],
1491 q = query.Query(fielddefs, ["name"], namefield="name",
1492 filter_=["!=", "name", "node1"])
1493 self.assertTrue(q.RequestedNames() is None)
1494 self.assertEqual(q.Query(data), [
1495 [(constants.RS_NORMAL, "node2.example.com")],
1496 [(constants.RS_NORMAL, "node2.example.net")],
1498 self.assertEqual(q.OldStyleQuery(data), [
1499 ["node2.example.com"],
1500 ["node2.example.net"],
1503 def testFilterBoolean(self):
1504 fielddefs = query._PrepareFieldList([
1505 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1506 None, query.QFF_HOSTNAME, lambda ctx, item: item["name"]),
1507 (query._MakeField("value", "Value", constants.QFT_BOOL, "Value"),
1508 None, 0, lambda ctx, item: item["value"]),
1512 { "name": "node1", "value": False, },
1513 { "name": "node2", "value": True, },
1514 { "name": "node3", "value": True, },
1517 q = query.Query(fielddefs, ["name", "value"],
1518 filter_=["|", ["=", "value", False],
1519 ["=", "value", True]])
1520 self.assertTrue(q.RequestedNames() is None)
1521 self.assertEqual(q.Query(data), [
1522 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1523 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1524 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1527 q = query.Query(fielddefs, ["name", "value"],
1528 filter_=["|", ["=", "value", False],
1529 ["!", ["=", "value", False]]])
1530 self.assertTrue(q.RequestedNames() is None)
1531 self.assertEqual(q.Query(data), [
1532 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1533 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1534 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1537 # Comparing bool with string
1538 for i in ["False", "True", "0", "1", "no", "yes", "N", "Y"]:
1539 self.assertRaises(errors.ParameterError, query.Query,
1540 fielddefs, ["name", "value"],
1541 filter_=["=", "value", i])
1544 q = query.Query(fielddefs, ["name", "value"], filter_=["?", "value"])
1545 self.assertTrue(q.RequestedNames() is None)
1546 self.assertEqual(q.Query(data), [
1547 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1548 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1551 # Negative bool filter
1552 q = query.Query(fielddefs, ["name", "value"], filter_=["!", ["?", "value"]])
1553 self.assertTrue(q.RequestedNames() is None)
1554 self.assertEqual(q.Query(data), [
1555 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1558 # Complex truth filter
1559 q = query.Query(fielddefs, ["name", "value"],
1560 filter_=["|", ["&", ["=", "name", "node1"],
1561 ["!", ["?", "value"]]],
1563 self.assertTrue(q.RequestedNames() is None)
1564 self.assertEqual(q.Query(data), [
1565 [(constants.RS_NORMAL, "node1"), (constants.RS_NORMAL, False)],
1566 [(constants.RS_NORMAL, "node2"), (constants.RS_NORMAL, True)],
1567 [(constants.RS_NORMAL, "node3"), (constants.RS_NORMAL, True)],
1570 def testFilterRegex(self):
1571 fielddefs = query._PrepareFieldList([
1572 (query._MakeField("name", "Name", constants.QFT_TEXT, "Name"),
1573 None, 0, lambda ctx, item: item["name"]),
1577 { "name": "node1.example.com", },
1578 { "name": "node2.site.example.com", },
1579 { "name": "node2.example.net", },
1585 q = query.Query(fielddefs, ["name"], namefield="name",
1586 filter_=["=~", "name", "site"])
1587 self.assertTrue(q.RequestedNames() is None)
1588 self.assertEqual(q.Query(data), [
1589 [(constants.RS_NORMAL, "node2.site.example.com")],
1592 q = query.Query(fielddefs, ["name"], namefield="name",
1593 filter_=["=~", "name", "^node2"])
1594 self.assertTrue(q.RequestedNames() is None)
1595 self.assertEqual(q.Query(data), [
1596 [(constants.RS_NORMAL, "node2.example.net")],
1597 [(constants.RS_NORMAL, "node2.site.example.com")],
1600 q = query.Query(fielddefs, ["name"], namefield="name",
1601 filter_=["=~", "name", r"(?i)\.COM$"])
1602 self.assertTrue(q.RequestedNames() is None)
1603 self.assertEqual(q.Query(data), [
1604 [(constants.RS_NORMAL, "node1.example.com")],
1605 [(constants.RS_NORMAL, "node2.site.example.com")],
1608 q = query.Query(fielddefs, ["name"], namefield="name",
1609 filter_=["=~", "name", r"."])
1610 self.assertTrue(q.RequestedNames() is None)
1611 self.assertEqual(q.Query(data), [
1612 [(constants.RS_NORMAL, "node1.example.com")],
1613 [(constants.RS_NORMAL, "node2.example.net")],
1614 [(constants.RS_NORMAL, "node2.site.example.com")],
1617 q = query.Query(fielddefs, ["name"], namefield="name",
1618 filter_=["=~", "name", r"^$"])
1619 self.assertTrue(q.RequestedNames() is None)
1620 self.assertEqual(q.Query(data), [
1621 [(constants.RS_NORMAL, "")],
1624 # Invalid regular expression
1625 self.assertRaises(errors.ParameterError, query.Query, fielddefs, ["name"],
1626 filter_=["=~", "name", r"["])
1629 if __name__ == "__main__":
1630 testutils.GanetiTestProgram()