4 # Copyright (C) 2010 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):
59 return (constants.QRFS_NORMAL, disks[nr])
61 return (constants.QRFS_UNAVAIL, None)
64 class TestQuery(unittest.TestCase):
66 (STATIC, DISK) = range(10, 12)
68 fielddef = query._PrepareFieldList([
69 (query._MakeField("name", "Name", constants.QFT_TEXT),
70 STATIC, lambda ctx, item: (constants.QRFS_NORMAL, item["name"])),
71 (query._MakeField("master", "Master", constants.QFT_BOOL),
72 STATIC, lambda ctx, item: (constants.QRFS_NORMAL,
73 ctx.mastername == item["name"])),
75 [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
77 DISK, compat.partial(_GetDiskSize, i))
80 q = query.Query(fielddef, ["name"])
81 self.assertEqual(q.RequestedData(), set([STATIC]))
82 self.assertEqual(len(q._fields), 1)
83 self.assertEqual(len(q.GetFields()), 1)
84 self.assertEqual(q.GetFields()[0].ToDict(),
85 objects.QueryFieldDefinition(name="name",
87 kind=constants.QFT_TEXT).ToDict())
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.QRFS_NORMAL, "node1")],
98 [(constants.QRFS_NORMAL, "node2")],
99 [(constants.QRFS_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.QRFS_NORMAL, "node1"),
108 (constants.QRFS_NORMAL, False)],
109 [(constants.QRFS_NORMAL, "node2"),
110 (constants.QRFS_NORMAL, False)],
111 [(constants.QRFS_NORMAL, "node3"),
112 (constants.QRFS_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.QRFS_NORMAL, "node1"),
120 (constants.QRFS_NORMAL, False),
121 (constants.QRFS_NORMAL, 0)],
122 [(constants.QRFS_NORMAL, "node2"),
123 (constants.QRFS_NORMAL, True),
124 (constants.QRFS_NORMAL, 3)],
125 [(constants.QRFS_NORMAL, "node3"),
126 (constants.QRFS_NORMAL, False),
127 (constants.QRFS_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.QRFS_NORMAL, 2),
137 (constants.QRFS_NORMAL, 1),
138 (constants.QRFS_UNKNOWN, None),
139 (constants.QRFS_NORMAL, 0)],
140 [(constants.QRFS_UNAVAIL, None),
141 (constants.QRFS_NORMAL, 4),
142 (constants.QRFS_UNKNOWN, None),
143 (constants.QRFS_NORMAL, 3)],
144 [(constants.QRFS_NORMAL, 7),
145 (constants.QRFS_NORMAL, 6),
146 (constants.QRFS_UNKNOWN, None),
147 (constants.QRFS_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, },
154 { "name": "disk1.size", "title": "DiskSize1",
155 "kind": constants.QFT_UNIT, },
156 { "name": "disk99.size", "title": "disk99.size",
157 "kind": constants.QFT_UNKNOWN, },
158 { "name": "disk0.size", "title": "DiskSize0",
159 "kind": constants.QFT_UNIT, },
163 q = query.Query(fielddef, [])
164 self.assertEqual(q.RequestedData(), set([]))
165 self.assertEqual(len(q._fields), 0)
166 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
168 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node2")),
170 self.assertEqual(q.GetFields(), [])
172 def testPrepareFieldList(self):
174 for (a, b) in [("name", "name"), ("NAME", "name")]:
175 self.assertRaises(AssertionError, query._PrepareFieldList, [
176 (query._MakeField("name", b, constants.QFT_TEXT), None,
178 (query._MakeField("other", a, constants.QFT_TEXT), None,
182 # Non-lowercase names
183 self.assertRaises(AssertionError, query._PrepareFieldList, [
184 (query._MakeField("NAME", "Name", constants.QFT_TEXT), None,
187 self.assertRaises(AssertionError, query._PrepareFieldList, [
188 (query._MakeField("Name", "Name", constants.QFT_TEXT), None,
193 self.assertRaises(AssertionError, query._PrepareFieldList, [
194 (query._MakeField("", "Name", constants.QFT_TEXT), None,
199 self.assertRaises(AssertionError, query._PrepareFieldList, [
200 (query._MakeField("name", "", constants.QFT_TEXT), None,
204 # Whitespace in title
205 self.assertRaises(AssertionError, query._PrepareFieldList, [
206 (query._MakeField("name", "Co lu mn", constants.QFT_TEXT), None,
210 # No callable function
211 self.assertRaises(AssertionError, query._PrepareFieldList, [
212 (query._MakeField("name", "Name", constants.QFT_TEXT), None, None),
215 def testUnknown(self):
216 fielddef = query._PrepareFieldList([
217 (query._MakeField("name", "Name", constants.QFT_TEXT),
218 None, lambda _, item: (constants.QRFS_NORMAL, "name%s" % item)),
219 (query._MakeField("other0", "Other0", constants.QFT_TIMESTAMP),
220 None, lambda *args: (constants.QRFS_NORMAL, 1234)),
221 (query._MakeField("nodata", "NoData", constants.QFT_NUMBER),
222 None, lambda *args: (constants.QRFS_NODATA, None)),
223 (query._MakeField("unavail", "Unavail", constants.QFT_BOOL),
224 None, lambda *args: (constants.QRFS_UNAVAIL, None)),
227 for selected in [["foo"], ["Hello", "World"],
228 ["name1", "other", "foo"]]:
229 q = query.Query(fielddef, selected)
230 self.assertEqual(len(q._fields), len(selected))
231 self.assert_(compat.all(len(row) == len(selected)
232 for row in q.Query(_QueryData(range(1, 10)))))
233 self.assertEqual(q.Query(_QueryData(range(1, 10))),
234 [[(constants.QRFS_UNKNOWN, None)] * len(selected)
235 for i in range(1, 10)])
236 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()],
237 [{ "name": name, "title": name,
238 "kind": constants.QFT_UNKNOWN, }
239 for name in selected])
241 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail"])
242 self.assertEqual(len(q._fields), 4)
243 self.assertEqual(q.OldStyleQuery(_QueryData(range(1, 10))), [
244 ["name%s" % i, 1234, None, None]
245 for i in range(1, 10)
248 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail", "unk"])
249 self.assertEqual(len(q._fields), 5)
250 self.assertEqual(q.Query(_QueryData(range(1, 10))),
251 [[(constants.QRFS_NORMAL, "name%s" % i),
252 (constants.QRFS_NORMAL, 1234),
253 (constants.QRFS_NODATA, None),
254 (constants.QRFS_UNAVAIL, None),
255 (constants.QRFS_UNKNOWN, None)]
256 for i in range(1, 10)])
259 class TestGetNodeRole(unittest.TestCase):
260 def testMaster(self):
261 node = objects.Node(name="node1")
262 self.assertEqual(query._GetNodeRole(node, "node1"), "M")
264 def testMasterCandidate(self):
265 node = objects.Node(name="node1", master_candidate=True)
266 self.assertEqual(query._GetNodeRole(node, "master"), "C")
268 def testRegular(self):
269 node = objects.Node(name="node1")
270 self.assertEqual(query._GetNodeRole(node, "master"), "R")
272 def testDrained(self):
273 node = objects.Node(name="node1", drained=True)
274 self.assertEqual(query._GetNodeRole(node, "master"), "D")
276 def testOffline(self):
277 node = objects.Node(name="node1", offline=True)
278 self.assertEqual(query._GetNodeRole(node, "master"), "O")
281 class TestNodeQuery(unittest.TestCase):
282 def _Create(self, selected):
283 return query.Query(query.NODE_FIELDS, selected)
285 def testSimple(self):
287 objects.Node(name="node1", drained=False),
288 objects.Node(name="node2", drained=True),
289 objects.Node(name="node3", drained=False),
291 for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]:
292 nqd = query.NodeQueryData(nodes, live_data, None, None, None, None, None)
294 q = self._Create(["name", "drained"])
295 self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG]))
296 self.assertEqual(q.Query(nqd),
297 [[(constants.QRFS_NORMAL, "node1"),
298 (constants.QRFS_NORMAL, False)],
299 [(constants.QRFS_NORMAL, "node2"),
300 (constants.QRFS_NORMAL, True)],
301 [(constants.QRFS_NORMAL, "node3"),
302 (constants.QRFS_NORMAL, False)],
304 self.assertEqual(q.OldStyleQuery(nqd),
310 selected = query.NODE_FIELDS.keys()
311 field_index = dict((field, idx) for idx, field in enumerate(selected))
313 q = self._Create(selected)
314 self.assertEqual(q.RequestedData(),
315 set([query.NQ_CONFIG, query.NQ_LIVE, query.NQ_INST,
316 query.NQ_GROUP, query.NQ_OOB]))
318 node_names = ["node%s" % i for i in range(20)]
319 master_name = node_names[3]
321 objects.Node(name=name,
322 primary_ip="192.0.2.%s" % idx,
323 secondary_ip="192.0.100.%s" % idx,
324 serial_no=7789 * idx,
325 master_candidate=(name != master_name and idx % 3 == 0),
329 master_capable=False,
333 uuid="fd9ccebe-6339-43c9-a82e-94bbe575%04d" % idx)
334 for idx, name in enumerate(node_names)
337 master_node = nodes[3]
338 master_node.AddTag("masternode")
339 master_node.AddTag("another")
340 master_node.AddTag("tag")
341 master_node.ctime = None
342 master_node.mtime = None
343 assert master_node.name == master_name
345 live_data_name = node_names[4]
346 assert live_data_name != master_name
349 "bootid": "a2504766-498e-4b25-b21e-d23098dc3af4",
356 "dfree": 5 * 1024 * 1024,
357 "dtotal": 100 * 1024 * 1024,
360 assert (sorted(query._NODE_LIVE_FIELDS.keys()) ==
361 sorted(fake_live_data.keys()))
363 live_data = dict.fromkeys(node_names, {})
364 live_data[live_data_name] = \
365 dict((query._NODE_LIVE_FIELDS[name][2], value)
366 for name, value in fake_live_data.items())
368 node_to_primary = dict((name, set()) for name in node_names)
369 node_to_primary[master_name].update(["inst1", "inst2"])
371 node_to_secondary = dict((name, set()) for name in node_names)
372 node_to_secondary[live_data_name].update(["instX", "instY", "instZ"])
374 ng_uuid = "492b4b74-8670-478a-b98d-4c53a76238e6"
376 ng_uuid: objects.NodeGroup(name="ng1", uuid=ng_uuid),
379 oob_support = dict((name, False) for name in node_names)
381 master_node.group = ng_uuid
383 nqd = query.NodeQueryData(nodes, live_data, master_name,
384 node_to_primary, node_to_secondary, groups,
386 result = q.Query(nqd)
387 self.assert_(compat.all(len(row) == len(selected) for row in result))
388 self.assertEqual([row[field_index["name"]] for row in result],
389 [(constants.QRFS_NORMAL, name) for name in node_names])
391 node_to_row = dict((row[field_index["name"]][1], idx)
392 for idx, row in enumerate(result))
394 master_row = result[node_to_row[master_name]]
395 self.assert_(master_row[field_index["master"]])
396 self.assert_(master_row[field_index["role"]], "M")
397 self.assertEqual(master_row[field_index["group"]],
398 (constants.QRFS_NORMAL, "ng1"))
399 self.assertEqual(master_row[field_index["group.uuid"]],
400 (constants.QRFS_NORMAL, ng_uuid))
401 self.assertEqual(master_row[field_index["ctime"]],
402 (constants.QRFS_UNAVAIL, None))
403 self.assertEqual(master_row[field_index["mtime"]],
404 (constants.QRFS_UNAVAIL, None))
406 self.assert_(row[field_index["pip"]] == node.primary_ip and
407 row[field_index["sip"]] == node.secondary_ip and
408 set(row[field_index["tags"]]) == node.GetTags() and
409 row[field_index["serial_no"]] == node.serial_no and
410 row[field_index["role"]] == query._GetNodeRole(node,
412 (node.name == master_name or
413 (row[field_index["group"]] == "<unknown>" and
414 row[field_index["group.uuid"]] is None and
415 row[field_index["ctime"]] == (constants.QRFS_NORMAL,
417 row[field_index["mtime"]] == (constants.QRFS_NORMAL,
419 for row, node in zip(result, nodes))
421 live_data_row = result[node_to_row[live_data_name]]
423 for (field, value) in fake_live_data.items():
424 self.assertEqual(live_data_row[field_index[field]],
425 (constants.QRFS_NORMAL, value))
427 self.assertEqual(master_row[field_index["pinst_cnt"]],
428 (constants.QRFS_NORMAL, 2))
429 self.assertEqual(live_data_row[field_index["sinst_cnt"]],
430 (constants.QRFS_NORMAL, 3))
431 self.assertEqual(master_row[field_index["pinst_list"]],
432 (constants.QRFS_NORMAL,
433 list(node_to_primary[master_name])))
434 self.assertEqual(live_data_row[field_index["sinst_list"]],
435 (constants.QRFS_NORMAL,
436 list(node_to_secondary[live_data_name])))
438 def testGetLiveNodeField(self):
440 objects.Node(name="node1", drained=False, offline=False),
441 objects.Node(name="node2", drained=True, offline=False),
442 objects.Node(name="node3", drained=False, offline=False),
443 objects.Node(name="node4", drained=False, offline=True),
445 live_data = dict.fromkeys([node.name for node in nodes], {})
448 nqd = query.NodeQueryData(None, None, None, None, None, None, None)
449 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
451 (constants.QRFS_NODATA, None))
454 ctx = _QueryData(None, curlive_data={
458 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
460 (constants.QRFS_UNAVAIL, None))
462 # Wrong format/datatype
463 ctx = _QueryData(None, curlive_data={
464 "hello": ["Hello World"],
467 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
469 (constants.QRFS_UNAVAIL, None))
472 assert nodes[3].offline
473 ctx = _QueryData(None, curlive_data={})
474 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
476 (constants.QRFS_OFFLINE, None))
479 ctx = _QueryData(None, curlive_data={"hello": 123})
480 self.assertRaises(AssertionError, query._GetLiveNodeField,
481 "hello", constants.QFT_BOOL, ctx, nodes[0])
484 class TestInstanceQuery(unittest.TestCase):
485 def _Create(self, selected):
486 return query.Query(query.INSTANCE_FIELDS, selected)
488 def testSimple(self):
489 q = self._Create(["name", "be/memory", "ip"])
490 self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
492 cluster = objects.Cluster(cluster_name="testcluster",
493 hvparams=constants.HVC_DEFAULTS,
495 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
498 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
502 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[]),
503 objects.Instance(name="inst2", hvparams={}, nics=[],
505 constants.BE_MEMORY: 512,
507 objects.Instance(name="inst3", hvparams={}, beparams={},
508 nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
511 iqd = query.InstanceQueryData(instances, cluster, None, [], [], {})
512 self.assertEqual(q.Query(iqd),
513 [[(constants.QRFS_NORMAL, "inst1"),
514 (constants.QRFS_NORMAL, 128),
515 (constants.QRFS_UNAVAIL, None),
517 [(constants.QRFS_NORMAL, "inst2"),
518 (constants.QRFS_NORMAL, 512),
519 (constants.QRFS_UNAVAIL, None),
521 [(constants.QRFS_NORMAL, "inst3"),
522 (constants.QRFS_NORMAL, 128),
523 (constants.QRFS_NORMAL, "192.0.2.99"),
525 self.assertEqual(q.OldStyleQuery(iqd),
526 [["inst1", 128, None],
527 ["inst2", 512, None],
528 ["inst3", 128, "192.0.2.99"]])
531 selected = query.INSTANCE_FIELDS.keys()
532 fieldidx = dict((field, idx) for idx, field in enumerate(selected))
534 macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
537 q = self._Create(selected)
538 self.assertEqual(q.RequestedData(),
539 set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE]))
541 cluster = objects.Cluster(cluster_name="testcluster",
542 hvparams=constants.HVC_DEFAULTS,
544 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
547 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
550 tcpudp_port_pool=set())
552 offline_nodes = ["nodeoff1", "nodeoff2"]
553 bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
554 nodes = ["node%s" % i for i in range(10)] + bad_nodes
557 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
558 uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
559 ctime=1291244000, mtime=1291244400, serial_no=30,
560 admin_up=True, hypervisor=constants.HT_XEN_PVM, os="linux1",
561 primary_node="node1",
562 disk_template=constants.DT_PLAIN,
564 objects.Instance(name="inst2", hvparams={}, nics=[],
565 uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
566 ctime=1291211000, mtime=1291211077, serial_no=1,
567 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
568 primary_node="node5",
569 disk_template=constants.DT_DISKLESS,
572 constants.BE_MEMORY: 512,
574 objects.Instance(name="inst3", hvparams={}, beparams={},
575 uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
576 ctime=1291011000, mtime=1291013000, serial_no=1923,
577 admin_up=False, hypervisor=constants.HT_KVM, os="busybox",
578 primary_node="node6",
579 disk_template=constants.DT_DRBD8,
582 objects.NIC(ip="192.0.2.99", mac=macs.pop(),
584 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
586 objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
588 objects.Instance(name="inst4", hvparams={}, beparams={},
589 uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
590 ctime=1291244390, mtime=1291244395, serial_no=25,
591 admin_up=False, hypervisor=constants.HT_XEN_PVM, os="linux1",
592 primary_node="nodeoff2",
593 disk_template=constants.DT_DRBD8,
596 objects.NIC(ip="192.0.2.1", mac=macs.pop(),
598 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
600 objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
601 objects.NIC(ip="192.0.2.3", mac=macs.pop(),
603 constants.NIC_MODE: constants.NIC_MODE_ROUTED,
605 objects.NIC(ip="192.0.2.4", mac=macs.pop(),
607 constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
608 constants.NIC_LINK: "eth123",
611 objects.Instance(name="inst5", hvparams={}, nics=[],
612 uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
613 ctime=1231211000, mtime=1261200000, serial_no=3,
614 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
615 primary_node="nodebad2",
616 disk_template=constants.DT_DISKLESS,
619 constants.BE_MEMORY: 512,
621 objects.Instance(name="inst6", hvparams={}, nics=[],
622 uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
623 ctime=7513, mtime=11501, serial_no=13390,
624 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
625 primary_node="node7",
626 disk_template=constants.DT_DISKLESS,
629 constants.BE_MEMORY: 768,
631 objects.Instance(name="inst7", hvparams={}, nics=[],
632 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
633 ctime=None, mtime=None, serial_no=1947,
634 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
635 primary_node="node6",
636 disk_template=constants.DT_DISKLESS,
641 assert not utils.FindDuplicates(inst.name for inst in instances)
643 disk_usage = dict((inst.name,
644 cmdlib._ComputeDiskSize(inst.disk_template,
646 for disk in inst.disks]))
647 for inst in instances)
650 "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
651 "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
667 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
668 offline_nodes, bad_nodes, live_data)
669 result = q.Query(iqd)
670 self.assertEqual(len(result), len(instances))
671 self.assert_(compat.all(len(row) == len(selected)
674 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
675 "Offline nodes not included in bad nodes"
677 tested_status = set()
679 for (inst, row) in zip(instances, result):
680 assert inst.primary_node in nodes
682 self.assertEqual(row[fieldidx["name"]],
683 (constants.QRFS_NORMAL, inst.name))
685 if inst.primary_node in offline_nodes:
686 exp_status = "ERROR_nodeoffline"
687 elif inst.primary_node in bad_nodes:
688 exp_status = "ERROR_nodedown"
689 elif inst.name in live_data:
691 exp_status = "running"
693 exp_status = "ERROR_up"
695 exp_status = "ERROR_down"
697 exp_status = "ADMIN_down"
699 self.assertEqual(row[fieldidx["status"]],
700 (constants.QRFS_NORMAL, exp_status))
702 (_, status) = row[fieldidx["status"]]
703 tested_status.add(status)
705 for (field, livefield) in [("oper_ram", "memory"),
706 ("oper_vcpus", "vcpus")]:
707 if inst.primary_node in bad_nodes:
708 exp = (constants.QRFS_NODATA, None)
709 elif inst.name in live_data:
710 value = live_data[inst.name].get(livefield, None)
712 exp = (constants.QRFS_UNAVAIL, None)
714 exp = (constants.QRFS_NORMAL, value)
716 exp = (constants.QRFS_UNAVAIL, None)
718 self.assertEqual(row[fieldidx[field]], exp)
720 bridges = inst_bridges.get(inst.name, [])
721 self.assertEqual(row[fieldidx["nic.bridges"]],
722 (constants.QRFS_NORMAL, bridges))
724 self.assertEqual(row[fieldidx["bridge"]],
725 (constants.QRFS_NORMAL, bridges[0]))
727 self.assertEqual(row[fieldidx["bridge"]],
728 (constants.QRFS_UNAVAIL, None))
730 for i in range(constants.MAX_NICS):
731 if i < len(bridges) and bridges[i] is not None:
732 exp = (constants.QRFS_NORMAL, bridges[i])
734 exp = (constants.QRFS_UNAVAIL, None)
735 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
737 if inst.primary_node in bad_nodes:
738 exp = (constants.QRFS_NODATA, None)
740 exp = (constants.QRFS_NORMAL, inst.name in live_data)
741 self.assertEqual(row[fieldidx["oper_state"]], exp)
743 usage = disk_usage[inst.name]
746 self.assertEqual(row[fieldidx["disk_usage"]],
747 (constants.QRFS_NORMAL, usage))
749 self.assertEqual(row[fieldidx["sda_size"]], row[fieldidx["disk.size/0"]])
750 self.assertEqual(row[fieldidx["sdb_size"]], row[fieldidx["disk.size/1"]])
752 for field in ["ctime", "mtime"]:
753 if getattr(inst, field) is None:
755 exp = (constants.QRFS_UNAVAIL, None)
757 exp = (constants.QRFS_NORMAL, getattr(inst, field))
758 self.assertEqual(row[fieldidx[field]], exp)
760 # Ensure all possible status' have been tested
761 self.assertEqual(tested_status,
762 set(["ERROR_nodeoffline", "ERROR_nodedown",
763 "running", "ERROR_up", "ERROR_down",
767 class TestGroupQuery(unittest.TestCase):
771 objects.NodeGroup(name="default",
772 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
773 alloc_policy=constants.ALLOC_POLICY_PREFERRED),
774 objects.NodeGroup(name="restricted",
775 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
776 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
779 def _Create(self, selected):
780 return query.Query(query.GROUP_FIELDS, selected)
782 def testSimple(self):
783 q = self._Create(["name", "uuid", "alloc_policy"])
784 gqd = query.GroupQueryData(self.groups, None, None)
786 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
788 self.assertEqual(q.Query(gqd),
789 [[(constants.QRFS_NORMAL, "default"),
790 (constants.QRFS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
791 (constants.QRFS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
793 [(constants.QRFS_NORMAL, "restricted"),
794 (constants.QRFS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
795 (constants.QRFS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
801 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
802 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
805 q = self._Create(["name", "node_cnt", "node_list"])
806 gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
808 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
810 self.assertEqual(q.Query(gqd),
811 [[(constants.QRFS_NORMAL, "default"),
812 (constants.QRFS_NORMAL, 2),
813 (constants.QRFS_NORMAL, ["node1", "node2"]),
815 [(constants.QRFS_NORMAL, "restricted"),
816 (constants.QRFS_NORMAL, 3),
817 (constants.QRFS_NORMAL, ["node1", "node9", "node10"]),
821 def testInstances(self):
822 groups_to_instances = {
823 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
824 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
827 q = self._Create(["pinst_cnt", "pinst_list"])
828 gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
830 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
832 self.assertEqual(q.Query(gqd),
833 [[(constants.QRFS_NORMAL, 2),
834 (constants.QRFS_NORMAL, ["inst1", "inst2"]),
836 [(constants.QRFS_NORMAL, 3),
837 (constants.QRFS_NORMAL, ["inst1", "inst9", "inst10"]),
842 class TestQueryFields(unittest.TestCase):
843 def testAllFields(self):
844 for fielddefs in query.ALL_FIELD_LISTS:
845 result = query.QueryFields(fielddefs, None)
846 self.assert_(isinstance(result, dict))
847 response = objects.QueryFieldsResponse.FromDict(result)
848 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
849 [(fdef2.name, fdef2.title)
850 for (fdef2, _, _) in utils.NiceSort(fielddefs.values(),
851 key=lambda x: x[0].name)])
853 def testSomeFields(self):
854 rnd = random.Random(5357)
857 for fielddefs in query.ALL_FIELD_LISTS:
858 if len(fielddefs) > 20:
859 sample_size = rnd.randint(5, 20)
861 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
862 fields = [fdef for (fdef, _, _) in rnd.sample(fielddefs.values(),
864 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
865 self.assert_(isinstance(result, dict))
866 response = objects.QueryFieldsResponse.FromDict(result)
867 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
868 [(fdef2.name, fdef2.title) for fdef2 in fields])
871 if __name__ == "__main__":
872 testutils.GanetiTestProgram()