diff --git a/lib/query.py b/lib/query.py index 2091190c4a4a5a6f39d1cb685ee0598af8c57f37..89681b82eb4fcddce8da825304f5708b290fa512 100644 --- a/lib/query.py +++ b/lib/query.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2010, 2011 Google Inc. +# Copyright (C) 2010, 2011, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -136,6 +136,12 @@ _VTToQFT = { _SERIAL_NO_DOC = "%s object serial number, incremented on each modification" +# TODO: Consider moving titles closer to constants +NDP_TITLE = { + constants.ND_OOB_PROGRAM: "OutOfBandProgram", + constants.ND_SPINDLE_COUNT: "SpindleCount", + } + def _GetUnknownField(ctx, item): # pylint: disable=W0613 """Gets the contents of an unknown field. @@ -899,6 +905,34 @@ def _GetItemAttr(attr): return lambda _, item: getter(item) +def _GetNDParam(name): + """Return a field function to return an ND parameter out of the context. + + """ + def _helper(ctx, _): + if ctx.ndparams is None: + return _FS_UNAVAIL + else: + return ctx.ndparams.get(name, None) + return _helper + + +def _BuildNDFields(is_group): + """Builds all the ndparam fields. + + @param is_group: whether this is called at group or node level + + """ + if is_group: + field_kind = GQ_CONFIG + else: + field_kind = NQ_GROUP + return [(_MakeField("ndp/%s" % name, NDP_TITLE.get(name, "ndp/%s" % name), + _VTToQFT[kind], "The \"%s\" node parameter" % name), + field_kind, 0, _GetNDParam(name)) + for name, kind in constants.NDS_PARAMETER_TYPES.items()] + + def _ConvWrapInner(convert, fn, ctx, item): """Wrapper for converting values. @@ -982,6 +1016,7 @@ class NodeQueryData: # Used for individual rows self.curlive_data = None + self.ndparams = None def __iter__(self): """Iterate over all nodes. @@ -991,6 +1026,11 @@ class NodeQueryData: """ for node in self.nodes: + group = self.groups.get(node.group, None) + if group is None: + self.ndparams = None + else: + self.ndparams = self.cluster.FillND(node, group) if self.live_data: self.curlive_data = self.live_data.get(node.name, None) else: @@ -1198,6 +1238,8 @@ def _BuildNodeFields(): NQ_CONFIG, 0, _GetNodeDiskState), ] + fields.extend(_BuildNDFields(False)) + # Node role role_values = (constants.NR_MASTER, constants.NR_MCANDIDATE, constants.NR_REGULAR, constants.NR_DRAINED, @@ -1959,6 +2001,7 @@ class GroupQueryData: # Used for individual rows self.group_ipolicy = None + self.ndparams = None def __iter__(self): """Iterate over all node groups. @@ -1969,6 +2012,7 @@ class GroupQueryData: """ for group in self.groups: self.group_ipolicy = self.cluster.SimpleFillIPolicy(group.ipolicy) + self.ndparams = self.cluster.SimpleFillND(group.ndparams) yield group @@ -1977,7 +2021,6 @@ _GROUP_SIMPLE_FIELDS = { "name": ("Group", QFT_TEXT, "Group name"), "serial_no": ("SerialNo", QFT_NUMBER, _SERIAL_NO_DOC % "Group"), "uuid": ("UUID", QFT_TEXT, "Group UUID"), - "ndparams": ("NDParams", QFT_OTHER, "Node parameters"), } @@ -2027,8 +2070,17 @@ def _BuildGroupFields(): (_MakeField("custom_ipolicy", "CustomInstancePolicy", QFT_OTHER, "Custom instance policy limitations"), GQ_CONFIG, 0, _GetItemAttr("ipolicy")), + (_MakeField("custom_ndparams", "CustomNDParams", QFT_OTHER, + "Custom node parameters"), + GQ_CONFIG, 0, _GetItemAttr("ndparams")), + (_MakeField("ndparams", "NDParams", QFT_OTHER, + "Node parameters"), + GQ_CONFIG, 0, lambda ctx, _: ctx.ndparams), ]) + # ND parameters + fields.extend(_BuildNDFields(True)) + fields.extend(_GetItemTimestampFields(GQ_CONFIG)) return _PrepareFieldList(fields, []) diff --git a/test/ganeti.query_unittest.py b/test/ganeti.query_unittest.py index 666eed40516b902dbd89ab81fa8f21c08d67e45b..caaa62680303c8d445532ae36118917386bda88e 100755 --- a/test/ganeti.query_unittest.py +++ b/test/ganeti.query_unittest.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -# Copyright (C) 2010, 2011 Google Inc. +# Copyright (C) 2010, 2011, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -322,14 +322,30 @@ class TestNodeQuery(unittest.TestCase): return query.Query(query.NODE_FIELDS, selected) def testSimple(self): + cluster = objects.Cluster(cluster_name="testcluster", + ndparams=constants.NDC_DEFAULTS.copy()) + grp1 = objects.NodeGroup(name="default", + uuid="c0e89160-18e7-11e0-a46e-001d0904baeb", + alloc_policy=constants.ALLOC_POLICY_PREFERRED, + ipolicy=objects.MakeEmptyIPolicy(), + ndparams={}, + ) + grp2 = objects.NodeGroup(name="group2", + uuid="c0e89160-18e7-11e0-a46e-001d0904babe", + alloc_policy=constants.ALLOC_POLICY_PREFERRED, + ipolicy=objects.MakeEmptyIPolicy(), + ndparams={constants.ND_SPINDLE_COUNT: 2}, + ) + groups = {grp1.uuid: grp1, grp2.uuid: grp2} nodes = [ - objects.Node(name="node1", drained=False), - objects.Node(name="node2", drained=True), - objects.Node(name="node3", drained=False), + objects.Node(name="node1", drained=False, group=grp1.uuid, ndparams={}), + objects.Node(name="node2", drained=True, group=grp2.uuid, ndparams={}), + objects.Node(name="node3", drained=False, group=grp1.uuid, + ndparams={constants.ND_SPINDLE_COUNT: 4}), ] for live_data in [None, dict.fromkeys([node.name for node in nodes], {})]: - nqd = query.NodeQueryData(nodes, live_data, None, None, None, None, None, - None) + nqd = query.NodeQueryData(nodes, live_data, None, None, None, + groups, None, cluster) q = self._Create(["name", "drained"]) self.assertEqual(q.RequestedData(), set([query.NQ_CONFIG])) @@ -345,6 +361,16 @@ class TestNodeQuery(unittest.TestCase): [["node1", False], ["node2", True], ["node3", False]]) + q = self._Create(["ndp/spindle_count"]) + self.assertEqual(q.RequestedData(), set([query.NQ_GROUP])) + self.assertEqual(q.Query(nqd), + [[(constants.RS_NORMAL, + constants.NDC_DEFAULTS[constants.ND_SPINDLE_COUNT])], + [(constants.RS_NORMAL, + grp2.ndparams[constants.ND_SPINDLE_COUNT])], + [(constants.RS_NORMAL, + nodes[2].ndparams[constants.ND_SPINDLE_COUNT])], + ]) def test(self): selected = query.NODE_FIELDS.keys() @@ -933,11 +959,15 @@ class TestGroupQuery(unittest.TestCase): objects.NodeGroup(name="default", uuid="c0e89160-18e7-11e0-a46e-001d0904baeb", alloc_policy=constants.ALLOC_POLICY_PREFERRED, - ipolicy=objects.MakeEmptyIPolicy()), + ipolicy=objects.MakeEmptyIPolicy(), + ndparams={}, + ), objects.NodeGroup(name="restricted", uuid="d2a40a74-18e7-11e0-9143-001d0904baeb", alloc_policy=constants.ALLOC_POLICY_LAST_RESORT, - ipolicy=objects.MakeEmptyIPolicy()), + ipolicy=objects.MakeEmptyIPolicy(), + ndparams={} + ), ] self.cluster = objects.Cluster(cluster_name="testcluster", hvparams=constants.HVC_DEFAULTS,