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,
714 wrongnode_inst = set("inst2")
716 consinfo = dict((inst.name, None) for inst in instances)
717 consinfo["inst7"] = \
718 objects.InstanceConsole(instance="inst7", kind=constants.CONS_SSH,
719 host=instbyname["inst7"].primary_node,
720 user=constants.GANETI_RUNAS,
721 command=["hostname"]).ToDict()
723 iqd = query.InstanceQueryData(instances, cluster, disk_usage,
724 offline_nodes, bad_nodes, live_data,
725 wrongnode_inst, consinfo)
726 result = q.Query(iqd)
727 self.assertEqual(len(result), len(instances))
728 self.assert_(compat.all(len(row) == len(selected)
731 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
732 "Offline nodes not included in bad nodes"
734 tested_status = set()
736 for (inst, row) in zip(instances, result):
737 assert inst.primary_node in nodes
739 self.assertEqual(row[fieldidx["name"]],
740 (constants.RS_NORMAL, inst.name))
742 if inst.primary_node in offline_nodes:
743 exp_status = "ERROR_nodeoffline"
744 elif inst.primary_node in bad_nodes:
745 exp_status = "ERROR_nodedown"
746 elif inst.name in live_data:
747 if inst.name in wrongnode_inst:
748 exp_status = "ERROR_wrongnode"
750 exp_status = "running"
752 exp_status = "ERROR_up"
754 exp_status = "ERROR_down"
756 exp_status = "ADMIN_down"
758 self.assertEqual(row[fieldidx["status"]],
759 (constants.RS_NORMAL, exp_status))
761 (_, status) = row[fieldidx["status"]]
762 tested_status.add(status)
764 for (field, livefield) in [("oper_ram", "memory"),
765 ("oper_vcpus", "vcpus")]:
766 if inst.primary_node in bad_nodes:
767 exp = (constants.RS_NODATA, None)
768 elif inst.name in live_data:
769 value = live_data[inst.name].get(livefield, None)
771 exp = (constants.RS_UNAVAIL, None)
773 exp = (constants.RS_NORMAL, value)
775 exp = (constants.RS_UNAVAIL, None)
777 self.assertEqual(row[fieldidx[field]], exp)
779 bridges = inst_bridges.get(inst.name, [])
780 self.assertEqual(row[fieldidx["nic.bridges"]],
781 (constants.RS_NORMAL, bridges))
783 self.assertEqual(row[fieldidx["bridge"]],
784 (constants.RS_NORMAL, bridges[0]))
786 self.assertEqual(row[fieldidx["bridge"]],
787 (constants.RS_UNAVAIL, None))
789 for i in range(constants.MAX_NICS):
790 if i < len(bridges) and bridges[i] is not None:
791 exp = (constants.RS_NORMAL, bridges[i])
793 exp = (constants.RS_UNAVAIL, None)
794 self.assertEqual(row[fieldidx["nic.bridge/%s" % i]], exp)
796 if inst.primary_node in bad_nodes:
797 exp = (constants.RS_NODATA, None)
799 exp = (constants.RS_NORMAL, inst.name in live_data)
800 self.assertEqual(row[fieldidx["oper_state"]], exp)
802 usage = disk_usage[inst.name]
805 self.assertEqual(row[fieldidx["disk_usage"]],
806 (constants.RS_NORMAL, usage))
808 self.assertEqual(row[fieldidx["sda_size"]], row[fieldidx["disk.size/0"]])
809 self.assertEqual(row[fieldidx["sdb_size"]], row[fieldidx["disk.size/1"]])
811 for field in ["ctime", "mtime"]:
812 if getattr(inst, field) is None:
814 exp = (constants.RS_UNAVAIL, None)
816 exp = (constants.RS_NORMAL, getattr(inst, field))
817 self.assertEqual(row[fieldidx[field]], exp)
819 self._CheckInstanceConsole(inst, row[fieldidx["console"]])
821 # Ensure all possible status' have been tested
822 self.assertEqual(tested_status,
823 set(["ERROR_nodeoffline", "ERROR_nodedown",
824 "running", "ERROR_up", "ERROR_down",
827 def _CheckInstanceConsole(self, instance, (status, consdata)):
828 if instance.name == "inst7":
829 self.assertEqual(status, constants.RS_NORMAL)
830 console = objects.InstanceConsole.FromDict(consdata)
831 self.assertTrue(console.Validate())
832 self.assertEqual(console.host, instance.primary_node)
834 self.assertEqual(status, constants.RS_UNAVAIL)
837 class TestGroupQuery(unittest.TestCase):
841 objects.NodeGroup(name="default",
842 uuid="c0e89160-18e7-11e0-a46e-001d0904baeb",
843 alloc_policy=constants.ALLOC_POLICY_PREFERRED),
844 objects.NodeGroup(name="restricted",
845 uuid="d2a40a74-18e7-11e0-9143-001d0904baeb",
846 alloc_policy=constants.ALLOC_POLICY_LAST_RESORT),
849 def _Create(self, selected):
850 return query.Query(query.GROUP_FIELDS, selected)
852 def testSimple(self):
853 q = self._Create(["name", "uuid", "alloc_policy"])
854 gqd = query.GroupQueryData(self.groups, None, None)
856 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG]))
858 self.assertEqual(q.Query(gqd),
859 [[(constants.RS_NORMAL, "default"),
860 (constants.RS_NORMAL, "c0e89160-18e7-11e0-a46e-001d0904baeb"),
861 (constants.RS_NORMAL, constants.ALLOC_POLICY_PREFERRED)
863 [(constants.RS_NORMAL, "restricted"),
864 (constants.RS_NORMAL, "d2a40a74-18e7-11e0-9143-001d0904baeb"),
865 (constants.RS_NORMAL, constants.ALLOC_POLICY_LAST_RESORT)
871 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["node1", "node2"],
872 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["node1", "node10", "node9"],
875 q = self._Create(["name", "node_cnt", "node_list"])
876 gqd = query.GroupQueryData(self.groups, groups_to_nodes, None)
878 self.assertEqual(q.RequestedData(), set([query.GQ_CONFIG, query.GQ_NODE]))
880 self.assertEqual(q.Query(gqd),
881 [[(constants.RS_NORMAL, "default"),
882 (constants.RS_NORMAL, 2),
883 (constants.RS_NORMAL, ["node1", "node2"]),
885 [(constants.RS_NORMAL, "restricted"),
886 (constants.RS_NORMAL, 3),
887 (constants.RS_NORMAL, ["node1", "node9", "node10"]),
891 def testInstances(self):
892 groups_to_instances = {
893 "c0e89160-18e7-11e0-a46e-001d0904baeb": ["inst1", "inst2"],
894 "d2a40a74-18e7-11e0-9143-001d0904baeb": ["inst1", "inst10", "inst9"],
897 q = self._Create(["pinst_cnt", "pinst_list"])
898 gqd = query.GroupQueryData(self.groups, None, groups_to_instances)
900 self.assertEqual(q.RequestedData(), set([query.GQ_INST]))
902 self.assertEqual(q.Query(gqd),
903 [[(constants.RS_NORMAL, 2),
904 (constants.RS_NORMAL, ["inst1", "inst2"]),
906 [(constants.RS_NORMAL, 3),
907 (constants.RS_NORMAL, ["inst1", "inst9", "inst10"]),
912 class TestQueryFields(unittest.TestCase):
913 def testAllFields(self):
914 for fielddefs in query.ALL_FIELD_LISTS:
915 result = query.QueryFields(fielddefs, None)
916 self.assert_(isinstance(result, dict))
917 response = objects.QueryFieldsResponse.FromDict(result)
918 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
919 [(fdef2.name, fdef2.title)
920 for (fdef2, _, _) in utils.NiceSort(fielddefs.values(),
921 key=lambda x: x[0].name)])
923 def testSomeFields(self):
924 rnd = random.Random(5357)
927 for fielddefs in query.ALL_FIELD_LISTS:
928 if len(fielddefs) > 20:
929 sample_size = rnd.randint(5, 20)
931 sample_size = rnd.randint(1, max(1, len(fielddefs) - 1))
932 fields = [fdef for (fdef, _, _) in rnd.sample(fielddefs.values(),
934 result = query.QueryFields(fielddefs, [fdef.name for fdef in fields])
935 self.assert_(isinstance(result, dict))
936 response = objects.QueryFieldsResponse.FromDict(result)
937 self.assertEqual([(fdef.name, fdef.title) for fdef in response.fields],
938 [(fdef2.name, fdef2.title) for fdef2 in fields])
941 if __name__ == "__main__":
942 testutils.GanetiTestProgram()