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,
473 objects.Node(name="node2", drained=True, offline=False,
475 objects.Node(name="node3", drained=False, offline=False,
477 objects.Node(name="node4", drained=False, offline=True,
479 objects.Node(name="node5", drained=False, offline=False,
482 live_data = dict.fromkeys([node.name for node in nodes], {})
485 nqd = query.NodeQueryData(None, None, None, None, None, None, None, None)
486 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
491 ctx = _QueryData(None, curlive_data={
495 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
499 # Wrong format/datatype
500 ctx = _QueryData(None, curlive_data={
501 "hello": ["Hello World"],
504 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
509 assert nodes[3].offline
510 ctx = _QueryData(None, curlive_data={})
511 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
513 query._FS_OFFLINE, None)
516 ctx = _QueryData(None, curlive_data={"hello": 123})
517 self.assertRaises(AssertionError, query._GetLiveNodeField,
518 "hello", constants.QFT_BOOL, ctx, nodes[0])
520 # Non-vm_capable node
521 assert not nodes[4].vm_capable
522 ctx = _QueryData(None, curlive_data={})
523 self.assertEqual(query._GetLiveNodeField("hello", constants.QFT_NUMBER,
525 query._FS_UNAVAIL, None)
528 class TestInstanceQuery(unittest.TestCase):
529 def _Create(self, selected):
530 return query.Query(query.INSTANCE_FIELDS, selected)
532 def testSimple(self):
533 q = self._Create(["name", "be/memory", "ip"])
534 self.assertEqual(q.RequestedData(), set([query.IQ_CONFIG]))
536 cluster = objects.Cluster(cluster_name="testcluster",
537 hvparams=constants.HVC_DEFAULTS,
539 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
542 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
546 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[]),
547 objects.Instance(name="inst2", hvparams={}, nics=[],
549 constants.BE_MEMORY: 512,
551 objects.Instance(name="inst3", hvparams={}, beparams={},
552 nics=[objects.NIC(ip="192.0.2.99", nicparams={})]),
555 iqd = query.InstanceQueryData(instances, cluster, None, [], [], {},
557 self.assertEqual(q.Query(iqd),
558 [[(constants.RS_NORMAL, "inst1"),
559 (constants.RS_NORMAL, 128),
560 (constants.RS_UNAVAIL, None),
562 [(constants.RS_NORMAL, "inst2"),
563 (constants.RS_NORMAL, 512),
564 (constants.RS_UNAVAIL, None),
566 [(constants.RS_NORMAL, "inst3"),
567 (constants.RS_NORMAL, 128),
568 (constants.RS_NORMAL, "192.0.2.99"),
570 self.assertEqual(q.OldStyleQuery(iqd),
571 [["inst1", 128, None],
572 ["inst2", 512, None],
573 ["inst3", 128, "192.0.2.99"]])
576 selected = query.INSTANCE_FIELDS.keys()
577 fieldidx = dict((field, idx) for idx, field in enumerate(selected))
579 macs = ["00:11:22:%02x:%02x:%02x" % (i % 255, i % 3, (i * 123) % 255)
582 q = self._Create(selected)
583 self.assertEqual(q.RequestedData(),
584 set([query.IQ_CONFIG, query.IQ_LIVE, query.IQ_DISKUSAGE,
587 cluster = objects.Cluster(cluster_name="testcluster",
588 hvparams=constants.HVC_DEFAULTS,
590 constants.PP_DEFAULT: constants.BEC_DEFAULTS,
593 constants.PP_DEFAULT: constants.NICC_DEFAULTS,
596 tcpudp_port_pool=set())
598 offline_nodes = ["nodeoff1", "nodeoff2"]
599 bad_nodes = ["nodebad1", "nodebad2", "nodebad3"] + offline_nodes
600 nodes = ["node%s" % i for i in range(10)] + bad_nodes
603 objects.Instance(name="inst1", hvparams={}, beparams={}, nics=[],
604 uuid="f90eccb3-e227-4e3c-bf2a-94a21ca8f9cd",
605 ctime=1291244000, mtime=1291244400, serial_no=30,
606 admin_up=True, hypervisor=constants.HT_XEN_PVM, os="linux1",
607 primary_node="node1",
608 disk_template=constants.DT_PLAIN,
610 objects.Instance(name="inst2", hvparams={}, nics=[],
611 uuid="73a0f8a7-068c-4630-ada2-c3440015ab1a",
612 ctime=1291211000, mtime=1291211077, serial_no=1,
613 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
614 primary_node="node5",
615 disk_template=constants.DT_DISKLESS,
618 constants.BE_MEMORY: 512,
620 objects.Instance(name="inst3", hvparams={}, beparams={},
621 uuid="11ec8dff-fb61-4850-bfe0-baa1803ff280",
622 ctime=1291011000, mtime=1291013000, serial_no=1923,
623 admin_up=False, hypervisor=constants.HT_KVM, os="busybox",
624 primary_node="node6",
625 disk_template=constants.DT_DRBD8,
628 objects.NIC(ip="192.0.2.99", mac=macs.pop(),
630 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
632 objects.NIC(ip=None, mac=macs.pop(), nicparams={}),
634 objects.Instance(name="inst4", hvparams={}, beparams={},
635 uuid="68dab168-3ef5-4c9d-b4d3-801e0672068c",
636 ctime=1291244390, mtime=1291244395, serial_no=25,
637 admin_up=False, hypervisor=constants.HT_XEN_PVM, os="linux1",
638 primary_node="nodeoff2",
639 disk_template=constants.DT_DRBD8,
642 objects.NIC(ip="192.0.2.1", mac=macs.pop(),
644 constants.NIC_LINK: constants.DEFAULT_BRIDGE,
646 objects.NIC(ip="192.0.2.2", mac=macs.pop(), nicparams={}),
647 objects.NIC(ip="192.0.2.3", mac=macs.pop(),
649 constants.NIC_MODE: constants.NIC_MODE_ROUTED,
651 objects.NIC(ip="192.0.2.4", mac=macs.pop(),
653 constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
654 constants.NIC_LINK: "eth123",
657 objects.Instance(name="inst5", hvparams={}, nics=[],
658 uuid="0e3dca12-5b42-4e24-98a2-415267545bd0",
659 ctime=1231211000, mtime=1261200000, serial_no=3,
660 admin_up=True, hypervisor=constants.HT_XEN_HVM, os="deb99",
661 primary_node="nodebad2",
662 disk_template=constants.DT_DISKLESS,
665 constants.BE_MEMORY: 512,
667 objects.Instance(name="inst6", hvparams={}, nics=[],
668 uuid="72de6580-c8d5-4661-b902-38b5785bb8b3",
669 ctime=7513, mtime=11501, serial_no=13390,
670 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
671 primary_node="node7",
672 disk_template=constants.DT_DISKLESS,
675 constants.BE_MEMORY: 768,
677 objects.Instance(name="inst7", hvparams={}, nics=[],
678 uuid="ceec5dc4-b729-4f42-ae28-69b3cd24920e",
679 ctime=None, mtime=None, serial_no=1947,
680 admin_up=False, hypervisor=constants.HT_XEN_HVM, os="deb99",
681 primary_node="node6",
682 disk_template=constants.DT_DISKLESS,
687 assert not utils.FindDuplicates(inst.name for inst in instances)
689 instbyname = dict((inst.name, inst) for inst in instances)
691 disk_usage = dict((inst.name,
692 cmdlib._ComputeDiskSize(inst.disk_template,
694 for disk in inst.disks]))
695 for inst in instances)
698 "inst3": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE],
699 "inst4": [constants.DEFAULT_BRIDGE, constants.DEFAULT_BRIDGE,
717 wrongnode_inst = set(["inst7"])
719 consinfo = dict((inst.name, None) for inst in instances)
720 consinfo["inst7"] = \
721 objects.InstanceConsole(instance="inst7", kind=constants.CONS_SSH,
722 host=instbyname["inst7"].primary_node,
723 user=constants.GANETI_RUNAS,
724 command=["hostname"]).ToDict()
726 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
727 offline_nodes, bad_nodes, live_data,
728 wrongnode_inst, consinfo)
729 result = q.Query(iqd)
730 self.assertEqual(len(result), len(instances))
731 self.assert_(compat.all(len(row) == len(selected)
734 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
735 "Offline nodes not included in bad nodes"
737 tested_status = set()
739 for (inst, row) in zip(instances, result):
740 assert inst.primary_node in nodes
742 self.assertEqual(row[fieldidx["name"]],
743 (constants.RS_NORMAL, inst.name))
745 if inst.primary_node in offline_nodes:
746 exp_status = "ERROR_nodeoffline"
747 elif inst.primary_node in bad_nodes:
748 exp_status = "ERROR_nodedown"
749 elif inst.name in live_data:
750 if inst.name in wrongnode_inst:
751 exp_status = "ERROR_wrongnode"
753 exp_status = "running"
755 exp_status = "ERROR_up"
757 exp_status = "ERROR_down"
759 exp_status = "ADMIN_down"
761 self.assertEqual(row[fieldidx["status"]],
762 (constants.RS_NORMAL, exp_status))
764 (_, status) = row[fieldidx["status"]]
765 tested_status.add(status)
767 for (field, livefield) in [("oper_ram", "memory"),
768 ("oper_vcpus", "vcpus")]:
769 if inst.primary_node in bad_nodes:
770 exp = (constants.RS_NODATA, None)
771 elif inst.name in live_data:
772 value = live_data[inst.name].get(livefield, None)
774 exp = (constants.RS_UNAVAIL, None)
776 exp = (constants.RS_NORMAL, value)
778 exp = (constants.RS_UNAVAIL, None)
780 self.assertEqual(row[fieldidx[field]], exp)
782 bridges = inst_bridges.get(inst.name, [])
783 self.assertEqual(row[fieldidx["nic.bridges"]],
784 (constants.RS_NORMAL, bridges))
786 self.assertEqual(row[fieldidx["bridge"]],
787 (constants.RS_NORMAL, bridges[0]))
789 self.assertEqual(row[fieldidx["bridge"]],
790 (constants.RS_UNAVAIL, None))
792 for i in range(constants.MAX_NICS):
793 if i < len(bridges) and bridges[i] is not None:
794 exp = (constants.RS_NORMAL, bridges[i])
796 exp = (constants.RS_UNAVAIL, None)
797 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
799 if inst.primary_node in bad_nodes:
800 exp = (constants.RS_NODATA, None)
802 exp = (constants.RS_NORMAL, inst.name in live_data)
803 self.assertEqual(row[fieldidx["oper_state"]], exp)
805 usage = disk_usage[inst.name]
808 self.assertEqual(row[fieldidx["disk_usage"]],
809 (constants.RS_NORMAL, usage))
811 self.assertEqual(row[fieldidx["sda_size"]], row[fieldidx["disk.size/0"]])
812 self.assertEqual(row[fieldidx["sdb_size"]], row[fieldidx["disk.size/1"]])
814 for field in ["ctime", "mtime"]:
815 if getattr(inst, field) is None:
817 exp = (constants.RS_UNAVAIL, None)
819 exp = (constants.RS_NORMAL, getattr(inst, field))
820 self.assertEqual(row[fieldidx[field]], exp)
822 self._CheckInstanceConsole(inst, row[fieldidx["console"]])
824 # Ensure all possible status' have been tested
825 self.assertEqual(tested_status,
826 set(["ERROR_nodeoffline", "ERROR_nodedown",
827 "running", "ERROR_up", "ERROR_down",
828 "ADMIN_down", "ERROR_wrongnode"]))
830 def _CheckInstanceConsole(self, instance, (status, consdata)):
831 if instance.name == "inst7":
832 self.assertEqual(status, constants.RS_NORMAL)
833 console = objects.InstanceConsole.FromDict(consdata)
834 self.assertTrue(console.Validate())
835 self.assertEqual(console.host, instance.primary_node)
837 self.assertEqual(status, constants.RS_UNAVAIL)
840 class TestGroupQuery(unittest.TestCase):
844 objects.NodeGroup(name="default",
845 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
846 alloc_policy=constants.ALLOC_POLICY_PREFERRED),
847 objects.NodeGroup(name="restricted",
848 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
849 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
852 def _Create(self, selected):
853 return query.Query(query.GROUP_FIELDS, selected)
855 def testSimple(self):
856 q = self._Create(["name", "uuid", "alloc_policy"])
857 gqd = query.GroupQueryData(self.groups, None, None)
859 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
861 self.assertEqual(q.Query(gqd),
862 [[(constants.RS_NORMAL, "default"),
863 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
864 (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
866 [(constants.RS_NORMAL, "restricted"),
867 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
868 (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
874 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
875 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
878 q = self._Create(["name", "node_cnt", "node_list"])
879 gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
881 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
883 self.assertEqual(q.Query(gqd),
884 [[(constants.RS_NORMAL, "default"),
885 (constants.RS_NORMAL, 2),
886 (constants.RS_NORMAL, ["node1", "node2"]),
888 [(constants.RS_NORMAL, "restricted"),
889 (constants.RS_NORMAL, 3),
890 (constants.RS_NORMAL, ["node1", "node9", "node10"]),
894 def testInstances(self):
895 groups_to_instances = {
896 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
897 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
900 q = self._Create(["pinst_cnt", "pinst_list"])
901 gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
903 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
905 self.assertEqual(q.Query(gqd),
906 [[(constants.RS_NORMAL, 2),
907 (constants.RS_NORMAL, ["inst1", "inst2"]),
909 [(constants.RS_NORMAL, 3),
910 (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
915 class TestQueryFields(unittest.TestCase):
916 def testAllFields(self):
917 for fielddefs in query.ALL_FIELD_LISTS:
918 result = query.QueryFields(fielddefs, None)
919 self.assert_(isinstance(result, dict))
920 response = objects.QueryFieldsResponse.FromDict(result)
921 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
922 [(fdef2.name, fdef2.title)
923 for (fdef2, _, _) in utils.NiceSort(fielddefs.values(),
924 key=lambda x: x[0].name)])
926 def testSomeFields(self):
927 rnd = random.Random(5357)
930 for fielddefs in query.ALL_FIELD_LISTS:
931 if len(fielddefs) > 20:
932 sample_size = rnd.randint(5, 20)
934 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
935 fields = [fdef for (fdef, _, _) in rnd.sample(fielddefs.values(),
937 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
938 self.assert_(isinstance(result, dict))
939 response = objects.QueryFieldsResponse.FromDict(result)
940 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
941 [(fdef2.name, fdef2.title) for fdef2 in fields])
944 if __name__ == "__main__":
945 testutils.GanetiTestProgram()