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),
70 STATIC, lambda ctx, item: item["name"]),
71 (query._MakeField("master", "Master", constants.QFT_BOOL),
72 STATIC, lambda ctx, item: ctx.mastername == item["name"]),
74 [(query._MakeField("disk%s.size" % i, "DiskSize%s" % i,
76 DISK, 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).ToDict())
88 # Create data only once query has been prepared
90 { "name": "node1", "disks": [0, 1, 2], },
91 { "name": "node2", "disks": [3, 4], },
92 { "name": "node3", "disks": [5, 6, 7], },
95 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
96 [[(constants.RS_NORMAL, "node1")],
97 [(constants.RS_NORMAL, "node2")],
98 [(constants.RS_NORMAL, "node3")]])
99 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node3")),
100 [["node1"], ["node2"], ["node3"]])
102 q = query.Query(fielddef, ["name", "master"])
103 self.assertEqual(q.RequestedData(), set([STATIC]))
104 self.assertEqual(len(q._fields), 2)
105 self.assertEqual(q.Query(_QueryData(data, mastername="node3")),
106 [[(constants.RS_NORMAL, "node1"),
107 (constants.RS_NORMAL, False)],
108 [(constants.RS_NORMAL, "node2"),
109 (constants.RS_NORMAL, False)],
110 [(constants.RS_NORMAL, "node3"),
111 (constants.RS_NORMAL, True)],
114 q = query.Query(fielddef, ["name", "master", "disk0.size"])
115 self.assertEqual(q.RequestedData(), set([STATIC, DISK]))
116 self.assertEqual(len(q._fields), 3)
117 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
118 [[(constants.RS_NORMAL, "node1"),
119 (constants.RS_NORMAL, False),
120 (constants.RS_NORMAL, 0)],
121 [(constants.RS_NORMAL, "node2"),
122 (constants.RS_NORMAL, True),
123 (constants.RS_NORMAL, 3)],
124 [(constants.RS_NORMAL, "node3"),
125 (constants.RS_NORMAL, False),
126 (constants.RS_NORMAL, 5)],
129 # With unknown column
130 q = query.Query(fielddef, ["disk2.size", "disk1.size", "disk99.size",
132 self.assertEqual(q.RequestedData(), set([DISK]))
133 self.assertEqual(len(q._fields), 4)
134 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
135 [[(constants.RS_NORMAL, 2),
136 (constants.RS_NORMAL, 1),
137 (constants.RS_UNKNOWN, None),
138 (constants.RS_NORMAL, 0)],
139 [(constants.RS_UNAVAIL, None),
140 (constants.RS_NORMAL, 4),
141 (constants.RS_UNKNOWN, None),
142 (constants.RS_NORMAL, 3)],
143 [(constants.RS_NORMAL, 7),
144 (constants.RS_NORMAL, 6),
145 (constants.RS_UNKNOWN, None),
146 (constants.RS_NORMAL, 5)],
148 self.assertRaises(errors.OpPrereqError, q.OldStyleQuery,
149 _QueryData(data, mastername="node2"))
150 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()], [
151 { "name": "disk2.size", "title": "DiskSize2",
152 "kind": constants.QFT_UNIT, },
153 { "name": "disk1.size", "title": "DiskSize1",
154 "kind": constants.QFT_UNIT, },
155 { "name": "disk99.size", "title": "disk99.size",
156 "kind": constants.QFT_UNKNOWN, },
157 { "name": "disk0.size", "title": "DiskSize0",
158 "kind": constants.QFT_UNIT, },
162 q = query.Query(fielddef, [])
163 self.assertEqual(q.RequestedData(), set([]))
164 self.assertEqual(len(q._fields), 0)
165 self.assertEqual(q.Query(_QueryData(data, mastername="node2")),
167 self.assertEqual(q.OldStyleQuery(_QueryData(data, mastername="node2")),
169 self.assertEqual(q.GetFields(), [])
171 def testPrepareFieldList(self):
173 for (a, b) in [("name", "name"), ("NAME", "name")]:
174 self.assertRaises(AssertionError, query._PrepareFieldList, [
175 (query._MakeField("name", b, constants.QFT_TEXT), None,
177 (query._MakeField("other", a, constants.QFT_TEXT), None,
181 # Non-lowercase names
182 self.assertRaises(AssertionError, query._PrepareFieldList, [
183 (query._MakeField("NAME", "Name", constants.QFT_TEXT), None,
186 self.assertRaises(AssertionError, query._PrepareFieldList, [
187 (query._MakeField("Name", "Name", constants.QFT_TEXT), None,
192 self.assertRaises(AssertionError, query._PrepareFieldList, [
193 (query._MakeField("", "Name", constants.QFT_TEXT), None,
198 self.assertRaises(AssertionError, query._PrepareFieldList, [
199 (query._MakeField("name", "", constants.QFT_TEXT), None,
203 # Whitespace in title
204 self.assertRaises(AssertionError, query._PrepareFieldList, [
205 (query._MakeField("name", "Co lu mn", constants.QFT_TEXT), None,
209 # No callable function
210 self.assertRaises(AssertionError, query._PrepareFieldList, [
211 (query._MakeField("name", "Name", constants.QFT_TEXT), None, None),
214 def testUnknown(self):
215 fielddef = query._PrepareFieldList([
216 (query._MakeField("name", "Name", constants.QFT_TEXT),
217 None, lambda _, item: "name%s" % item),
218 (query._MakeField("other0", "Other0", constants.QFT_TIMESTAMP),
219 None, lambda *args: 1234),
220 (query._MakeField("nodata", "NoData", constants.QFT_NUMBER),
221 None, lambda *args: query._FS_NODATA ),
222 (query._MakeField("unavail", "Unavail", constants.QFT_BOOL),
223 None, lambda *args: query._FS_UNAVAIL),
226 for selected in [["foo"], ["Hello", "World"],
227 ["name1", "other", "foo"]]:
228 q = query.Query(fielddef, selected)
229 self.assertEqual(len(q._fields), len(selected))
230 self.assert_(compat.all(len(row) == len(selected)
231 for row in q.Query(_QueryData(range(1, 10)))))
232 self.assertEqual(q.Query(_QueryData(range(1, 10))),
233 [[(constants.RS_UNKNOWN, None)] * len(selected)
234 for i in range(1, 10)])
235 self.assertEqual([fdef.ToDict() for fdef in q.GetFields()],
236 [{ "name": name, "title": name,
237 "kind": constants.QFT_UNKNOWN, }
238 for name in selected])
240 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail"])
241 self.assertEqual(len(q._fields), 4)
242 self.assertEqual(q.OldStyleQuery(_QueryData(range(1, 10))), [
243 ["name%s" % i, 1234, None, None]
244 for i in range(1, 10)
247 q = query.Query(fielddef, ["name", "other0", "nodata", "unavail", "unk"])
248 self.assertEqual(len(q._fields), 5)
249 self.assertEqual(q.Query(_QueryData(range(1, 10))),
250 [[(constants.RS_NORMAL, "name%s" % i),
251 (constants.RS_NORMAL, 1234),
252 (constants.RS_NODATA, None),
253 (constants.RS_UNAVAIL, None),
254 (constants.RS_UNKNOWN, None)]
255 for i in range(1, 10)])
257 def testAliases(self):
259 (query._MakeField("a", "a-title", constants.QFT_TEXT), None,
261 (query._MakeField("b", "b-title", constants.QFT_TEXT), None,
265 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
267 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
268 [("c", "b"), ("c", "a")])
270 self.assertRaises(AssertionError, query._PrepareFieldList, fields,
272 fdefs = query._PrepareFieldList(fields, [("c", "b")])
273 self.assertEqual(len(fdefs), 3)
274 self.assertEqual(fdefs["b"][1:], fdefs["c"][1:])
277 class TestGetNodeRole(unittest.TestCase):
278 def testMaster(self):
279 node = objects.Node(name="node1")
280 self.assertEqual(query._GetNodeRole(node, "node1"), "M")
282 def testMasterCandidate(self):
283 node = objects.Node(name="node1", master_candidate=True)
284 self.assertEqual(query._GetNodeRole(node, "master"), "C")
286 def testRegular(self):
287 node = objects.Node(name="node1")
288 self.assertEqual(query._GetNodeRole(node, "master"), "R")
290 def testDrained(self):
291 node = objects.Node(name="node1", drained=True)
292 self.assertEqual(query._GetNodeRole(node, "master"), "D")
294 def testOffline(self):
295 node = objects.Node(name="node1", offline=True)
296 self.assertEqual(query._GetNodeRole(node, "master"), "O")
299 class TestNodeQuery(unittest.TestCase):
300 def _Create(self, selected):
301 return query.Query(query.NODE_FIELDS, selected)
303 def testSimple(self):
305 objects.Node(name="node1", drained=False),
306 objects.Node(name="node2", drained=True),
307 objects.Node(name="node3", drained=False),
309 for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]:
310 nqd = query.NodeQueryData(nodes, live_data, None, None, None, None, None,
313 q = self._Create(["name", "drained"])
314 self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG]))
315 self.assertEqual(q.Query(nqd),
316 [[(constants.RS_NORMAL, "node1"),
317 (constants.RS_NORMAL, False)],
318 [(constants.RS_NORMAL, "node2"),
319 (constants.RS_NORMAL, True)],
320 [(constants.RS_NORMAL, "node3"),
321 (constants.RS_NORMAL, False)],
323 self.assertEqual(q.OldStyleQuery(nqd),
329 selected = query.NODE_FIELDS.keys()
330 field_index = dict((field, idx) for idx, field in enumerate(selected))
332 q = self._Create(selected)
333 self.assertEqual(q.RequestedData(),
334 set([query.NQ_CONFIG, query.NQ_LIVE, query.NQ_INST,
335 query.NQ_GROUP, query.NQ_OOB]))
337 cluster = objects.Cluster(cluster_name="testcluster",
338 hvparams=constants.HVC_DEFAULTS,
340 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
343 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
345 ndparams=constants.NDC_DEFAULTS,
348 node_names = ["node%s" % i for i in range(20)]
349 master_name = node_names[3]
351 objects.Node(name=name,
352 primary_ip="192.0.2.%s" % idx,
353 secondary_ip="192.0.100.%s" % idx,
354 serial_no=7789 * idx,
355 master_candidate=(name != master_name and idx % 3 == 0),
359 master_capable=False,
364 uuid="fd9ccebe-6339-43c9-a82e-94bbe575%04d" % idx)
365 for idx, name in enumerate(node_names)
368 master_node = nodes[3]
369 master_node.AddTag("masternode")
370 master_node.AddTag("another")
371 master_node.AddTag("tag")
372 master_node.ctime = None
373 master_node.mtime = None
374 assert master_node.name == master_name
376 live_data_name = node_names[4]
377 assert live_data_name != master_name
380 "bootid": "a2504766-498e-4b25-b21e-d23098dc3af4",
387 "dfree": 5 * 1024 * 1024,
388 "dtotal": 100 * 1024 * 1024,
391 assert (sorted(query._NODE_LIVE_FIELDS.keys()) ==
392 sorted(fake_live_data.keys()))
394 live_data = dict.fromkeys(node_names, {})
395 live_data[live_data_name] = \
396 dict((query._NODE_LIVE_FIELDS[name][2], value)
397 for name, value in fake_live_data.items())
399 node_to_primary = dict((name, set()) for name in node_names)
400 node_to_primary[master_name].update(["inst1", "inst2"])
402 node_to_secondary = dict((name, set()) for name in node_names)
403 node_to_secondary[live_data_name].update(["instX", "instY", "instZ"])
405 ng_uuid = "492b4b74-8670-478a-b98d-4c53a76238e6"
407 ng_uuid: objects.NodeGroup(name="ng1", uuid=ng_uuid, ndparams={}),
410 oob_support = dict((name, False) for name in node_names)
412 master_node.group = ng_uuid
414 nqd = query.NodeQueryData(nodes, live_data, master_name,
415 node_to_primary, node_to_secondary, groups,
416 oob_support, cluster)
417 result = q.Query(nqd)
418 self.assert_(compat.all(len(row) == len(selected) for row in result))
419 self.assertEqual([row[field_index["name"]] for row in result],
420 [(constants.RS_NORMAL, name) for name in node_names])
422 node_to_row = dict((row[field_index["name"]][1], idx)
423 for idx, row in enumerate(result))
425 master_row = result[node_to_row[master_name]]
426 self.assert_(master_row[field_index["master"]])
427 self.assert_(master_row[field_index["role"]], "M")
428 self.assertEqual(master_row[field_index["group"]],
429 (constants.RS_NORMAL, "ng1"))
430 self.assertEqual(master_row[field_index["group.uuid"]],
431 (constants.RS_NORMAL, ng_uuid))
432 self.assertEqual(master_row[field_index["ctime"]],
433 (constants.RS_UNAVAIL, None))
434 self.assertEqual(master_row[field_index["mtime"]],
435 (constants.RS_UNAVAIL, None))
437 self.assert_(row[field_index["pip"]] == node.primary_ip and
438 row[field_index["sip"]] == node.secondary_ip and
439 set(row[field_index["tags"]]) == node.GetTags() and
440 row[field_index["serial_no"]] == node.serial_no and
441 row[field_index["role"]] == query._GetNodeRole(node,
443 (node.name == master_name or
444 (row[field_index["group"]] == "<unknown>" and
445 row[field_index["group.uuid"]] is None and
446 row[field_index["ctime"]] == (constants.RS_NORMAL,
448 row[field_index["mtime"]] == (constants.RS_NORMAL,
450 for row, node in zip(result, nodes))
452 live_data_row = result[node_to_row[live_data_name]]
454 for (field, value) in fake_live_data.items():
455 self.assertEqual(live_data_row[field_index[field]],
456 (constants.RS_NORMAL, value))
458 self.assertEqual(master_row[field_index["pinst_cnt"]],
459 (constants.RS_NORMAL, 2))
460 self.assertEqual(live_data_row[field_index["sinst_cnt"]],
461 (constants.RS_NORMAL, 3))
462 self.assertEqual(master_row[field_index["pinst_list"]],
463 (constants.RS_NORMAL,
464 list(node_to_primary[master_name])))
465 self.assertEqual(live_data_row[field_index["sinst_list"]],
466 (constants.RS_NORMAL,
467 list(node_to_secondary[live_data_name])))
469 def testGetLiveNodeField(self):
471 objects.Node(name="node1", drained=False, offline=False),
472 objects.Node(name="node2", drained=True, offline=False),
473 objects.Node(name="node3", drained=False, offline=False),
474 objects.Node(name="node4", drained=False, offline=True),
476 live_data = dict.fromkeys([node.name for node in nodes], {})
479 nqd = query.NodeQueryData(None, None, None, None, None, None, None, None)
480 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
485 ctx = _QueryData(None, curlive_data={
489 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
493 # Wrong format/datatype
494 ctx = _QueryData(None, curlive_data={
495 "hello": ["Hello World"],
498 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
503 assert nodes[3].offline
504 ctx = _QueryData(None, curlive_data={})
505 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
507 query._FS_OFFLINE, None)
510 ctx = _QueryData(None, curlive_data={"hello": 123})
511 self.assertRaises(AssertionError, query._GetLiveNodeField,
512 "hello", constants.QFT_BOOL, ctx, nodes[0])
515 class TestInstanceQuery(unittest.TestCase):
516 def _Create(self, selected):
517 return query.Query(query.INSTANCE_FIELDS, selected)
519 def testSimple(self):
520 q = self._Create(["name", "be/memory", "ip"])
521 self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
523 cluster = objects.Cluster(cluster_name="testcluster",
524 hvparams=constants.HVC_DEFAULTS,
526 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
529 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
533 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[]),
534 objects.Instance(name="inst2", hvparams={}, nics=[],
536 constants.BE_MEMORY: 512,
538 objects.Instance(name="inst3", hvparams={}, beparams={},
539 nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
542 iqd = query.InstanceQueryData(instances, cluster, None, [], [], {})
543 self.assertEqual(q.Query(iqd),
544 [[(constants.RS_NORMAL, "inst1"),
545 (constants.RS_NORMAL, 128),
546 (constants.RS_UNAVAIL, None),
548 [(constants.RS_NORMAL, "inst2"),
549 (constants.RS_NORMAL, 512),
550 (constants.RS_UNAVAIL, None),
552 [(constants.RS_NORMAL, "inst3"),
553 (constants.RS_NORMAL, 128),
554 (constants.RS_NORMAL, "192.0.2.99"),
556 self.assertEqual(q.OldStyleQuery(iqd),
557 [["inst1", 128, None],
558 ["inst2", 512, None],
559 ["inst3", 128, "192.0.2.99"]])
562 selected = query.INSTANCE_FIELDS.keys()
563 fieldidx = dict((field, idx) for idx, field in enumerate(selected))
565 macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
568 q = self._Create(selected)
569 self.assertEqual(q.RequestedData(),
570 set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE]))
572 cluster = objects.Cluster(cluster_name="testcluster",
573 hvparams=constants.HVC_DEFAULTS,
575 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
578 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
581 tcpudp_port_pool=set())
583 offline_nodes = ["nodeoff1", "nodeoff2"]
584 bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
585 nodes = ["node%s" % i for i in range(10)] + bad_nodes
588 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
589 uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
590 ctime=1291244000, mtime=1291244400, serial_no=30,
591 admin_up=True, hypervisor=constants.HT_XEN_PVM, os="linux1",
592 primary_node="node1",
593 disk_template=constants.DT_PLAIN,
595 objects.Instance(name="inst2", hvparams={}, nics=[],
596 uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
597 ctime=1291211000, mtime=1291211077, serial_no=1,
598 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
599 primary_node="node5",
600 disk_template=constants.DT_DISKLESS,
603 constants.BE_MEMORY: 512,
605 objects.Instance(name="inst3", hvparams={}, beparams={},
606 uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
607 ctime=1291011000, mtime=1291013000, serial_no=1923,
608 admin_up=False, hypervisor=constants.HT_KVM, os="busybox",
609 primary_node="node6",
610 disk_template=constants.DT_DRBD8,
613 objects.NIC(ip="192.0.2.99", mac=macs.pop(),
615 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
617 objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
619 objects.Instance(name="inst4", hvparams={}, beparams={},
620 uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
621 ctime=1291244390, mtime=1291244395, serial_no=25,
622 admin_up=False, hypervisor=constants.HT_XEN_PVM, os="linux1",
623 primary_node="nodeoff2",
624 disk_template=constants.DT_DRBD8,
627 objects.NIC(ip="192.0.2.1", mac=macs.pop(),
629 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
631 objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
632 objects.NIC(ip="192.0.2.3", mac=macs.pop(),
634 constants.NIC_MODE: constants.NIC_MODE_ROUTED,
636 objects.NIC(ip="192.0.2.4", mac=macs.pop(),
638 constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
639 constants.NIC_LINK: "eth123",
642 objects.Instance(name="inst5", hvparams={}, nics=[],
643 uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
644 ctime=1231211000, mtime=1261200000, serial_no=3,
645 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
646 primary_node="nodebad2",
647 disk_template=constants.DT_DISKLESS,
650 constants.BE_MEMORY: 512,
652 objects.Instance(name="inst6", hvparams={}, nics=[],
653 uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
654 ctime=7513, mtime=11501, serial_no=13390,
655 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
656 primary_node="node7",
657 disk_template=constants.DT_DISKLESS,
660 constants.BE_MEMORY: 768,
662 objects.Instance(name="inst7", hvparams={}, nics=[],
663 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
664 ctime=None, mtime=None, serial_no=1947,
665 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
666 primary_node="node6",
667 disk_template=constants.DT_DISKLESS,
672 assert not utils.FindDuplicates(inst.name for inst in instances)
674 disk_usage = dict((inst.name,
675 cmdlib._ComputeDiskSize(inst.disk_template,
677 for disk in inst.disks]))
678 for inst in instances)
681 "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
682 "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
698 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
699 offline_nodes, bad_nodes, live_data)
700 result = q.Query(iqd)
701 self.assertEqual(len(result), len(instances))
702 self.assert_(compat.all(len(row) == len(selected)
705 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
706 "Offline nodes not included in bad nodes"
708 tested_status = set()
710 for (inst, row) in zip(instances, result):
711 assert inst.primary_node in nodes
713 self.assertEqual(row[fieldidx["name"]],
714 (constants.RS_NORMAL, inst.name))
716 if inst.primary_node in offline_nodes:
717 exp_status = "ERROR_nodeoffline"
718 elif inst.primary_node in bad_nodes:
719 exp_status = "ERROR_nodedown"
720 elif inst.name in live_data:
722 exp_status = "running"
724 exp_status = "ERROR_up"
726 exp_status = "ERROR_down"
728 exp_status = "ADMIN_down"
730 self.assertEqual(row[fieldidx["status"]],
731 (constants.RS_NORMAL, exp_status))
733 (_, status) = row[fieldidx["status"]]
734 tested_status.add(status)
736 for (field, livefield) in [("oper_ram", "memory"),
737 ("oper_vcpus", "vcpus")]:
738 if inst.primary_node in bad_nodes:
739 exp = (constants.RS_NODATA, None)
740 elif inst.name in live_data:
741 value = live_data[inst.name].get(livefield, None)
743 exp = (constants.RS_UNAVAIL, None)
745 exp = (constants.RS_NORMAL, value)
747 exp = (constants.RS_UNAVAIL, None)
749 self.assertEqual(row[fieldidx[field]], exp)
751 bridges = inst_bridges.get(inst.name, [])
752 self.assertEqual(row[fieldidx["nic.bridges"]],
753 (constants.RS_NORMAL, bridges))
755 self.assertEqual(row[fieldidx["bridge"]],
756 (constants.RS_NORMAL, bridges[0]))
758 self.assertEqual(row[fieldidx["bridge"]],
759 (constants.RS_UNAVAIL, None))
761 for i in range(constants.MAX_NICS):
762 if i < len(bridges) and bridges[i] is not None:
763 exp = (constants.RS_NORMAL, bridges[i])
765 exp = (constants.RS_UNAVAIL, None)
766 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
768 if inst.primary_node in bad_nodes:
769 exp = (constants.RS_NODATA, None)
771 exp = (constants.RS_NORMAL, inst.name in live_data)
772 self.assertEqual(row[fieldidx["oper_state"]], exp)
774 usage = disk_usage[inst.name]
777 self.assertEqual(row[fieldidx["disk_usage"]],
778 (constants.RS_NORMAL, usage))
780 self.assertEqual(row[fieldidx["sda_size"]], row[fieldidx["disk.size/0"]])
781 self.assertEqual(row[fieldidx["sdb_size"]], row[fieldidx["disk.size/1"]])
783 for field in ["ctime", "mtime"]:
784 if getattr(inst, field) is None:
786 exp = (constants.RS_UNAVAIL, None)
788 exp = (constants.RS_NORMAL, getattr(inst, field))
789 self.assertEqual(row[fieldidx[field]], exp)
791 # Ensure all possible status' have been tested
792 self.assertEqual(tested_status,
793 set(["ERROR_nodeoffline", "ERROR_nodedown",
794 "running", "ERROR_up", "ERROR_down",
798 class TestGroupQuery(unittest.TestCase):
802 objects.NodeGroup(name="default",
803 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
804 alloc_policy=constants.ALLOC_POLICY_PREFERRED),
805 objects.NodeGroup(name="restricted",
806 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
807 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
810 def _Create(self, selected):
811 return query.Query(query.GROUP_FIELDS, selected)
813 def testSimple(self):
814 q = self._Create(["name", "uuid", "alloc_policy"])
815 gqd = query.GroupQueryData(self.groups, None, None)
817 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
819 self.assertEqual(q.Query(gqd),
820 [[(constants.RS_NORMAL, "default"),
821 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
822 (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
824 [(constants.RS_NORMAL, "restricted"),
825 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
826 (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
832 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
833 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
836 q = self._Create(["name", "node_cnt", "node_list"])
837 gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
839 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
841 self.assertEqual(q.Query(gqd),
842 [[(constants.RS_NORMAL, "default"),
843 (constants.RS_NORMAL, 2),
844 (constants.RS_NORMAL, ["node1", "node2"]),
846 [(constants.RS_NORMAL, "restricted"),
847 (constants.RS_NORMAL, 3),
848 (constants.RS_NORMAL, ["node1", "node9", "node10"]),
852 def testInstances(self):
853 groups_to_instances = {
854 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
855 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
858 q = self._Create(["pinst_cnt", "pinst_list"])
859 gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
861 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
863 self.assertEqual(q.Query(gqd),
864 [[(constants.RS_NORMAL, 2),
865 (constants.RS_NORMAL, ["inst1", "inst2"]),
867 [(constants.RS_NORMAL, 3),
868 (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
873 class TestQueryFields(unittest.TestCase):
874 def testAllFields(self):
875 for fielddefs in query.ALL_FIELD_LISTS:
876 result = query.QueryFields(fielddefs, None)
877 self.assert_(isinstance(result, dict))
878 response = objects.QueryFieldsResponse.FromDict(result)
879 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
880 [(fdef2.name, fdef2.title)
881 for (fdef2, _, _) in utils.NiceSort(fielddefs.values(),
882 key=lambda x: x[0].name)])
884 def testSomeFields(self):
885 rnd = random.Random(5357)
888 for fielddefs in query.ALL_FIELD_LISTS:
889 if len(fielddefs) > 20:
890 sample_size = rnd.randint(5, 20)
892 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
893 fields = [fdef for (fdef, _, _) in rnd.sample(fielddefs.values(),
895 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
896 self.assert_(isinstance(result, dict))
897 response = objects.QueryFieldsResponse.FromDict(result)
898 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
899 [(fdef2.name, fdef2.title) for fdef2 in fields])
902 if __name__ == "__main__":
903 testutils.GanetiTestProgram()