X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/52b5d2863476953186804a131ca29291f742bb49..a6682fdcc173998be87b77043bfa56c0d12b1ca4:/lib/query.py diff --git a/lib/query.py b/lib/query.py index 55dc63f..86940f3 100644 --- a/lib/query.py +++ b/lib/query.py @@ -19,7 +19,36 @@ # 02110-1301, USA. -"""Module for query operations""" +"""Module for query operations + +How it works: + + - Add field definitions + - See how L{NODE_FIELDS} is built + - Each field gets: + - Query field definition (L{objects.QueryFieldDefinition}, use + L{_MakeField} for creating), containing: + - Name, must be lowercase and match L{FIELD_NAME_RE} + - Title for tables, must not contain whitespace and match + L{TITLE_RE} + - Value data type, e.g. L{constants.QFT_NUMBER} + - Data request type, see e.g. C{NQ_*} + - A retrieval function, see L{Query.__init__} for description + - Pass list of fields through L{_PrepareFieldList} for preparation and + checks + - Instantiate L{Query} with prepared field list definition and selected fields + - Call L{Query.RequestedData} to determine what data to collect/compute + - Call L{Query.Query} or L{Query.OldStyleQuery} with collected data and use + result + - Data container must support iteration using C{__iter__} + - Items are passed to retrieval functions and can have any format + - Call L{Query.GetFields} to get list of definitions for selected fields + +@attention: Retrieval functions must be idempotent. They can be called multiple + times, in any order and any number of times. This is important to keep in + mind for implementing filters in the future. + +""" import logging import operator @@ -33,6 +62,10 @@ from ganeti import objects from ganeti import ht +# Constants for requesting data from the caller/data provider. Each property +# collected/computed separately by the data provider should have its own to +# only collect the requested data and not more. + (NQ_CONFIG, NQ_INST, NQ_LIVE, @@ -213,7 +246,7 @@ def _PrepareFieldList(fields): @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind, retrieval function) - @param fields: List of fields + @param fields: List of fields, see L{Query.__init__} for a better description @rtype: dict @return: Field dictionary for L{Query} @@ -358,7 +391,7 @@ class NodeQueryData: """ def __init__(self, nodes, live_data, master_name, node_to_primary, - node_to_secondary, groups, oob_support): + node_to_secondary, groups, oob_support, cluster): """Initializes this class. """ @@ -369,6 +402,7 @@ class NodeQueryData: self.node_to_secondary = node_to_secondary self.groups = groups self.oob_support = oob_support + self.cluster = cluster # Used for individual rows self.curlive_data = None @@ -415,19 +449,40 @@ _NODE_LIVE_FIELDS = { } -def _GetNodeGroup(ctx, node): +def _GetGroup(cb): + """Build function for calling another function with an node group. + + @param cb: The callback to be called with the nodegroup + + """ + def fn(ctx, node): + """Get group data for a node. + + @type ctx: L{NodeQueryData} + @type inst: L{objects.Node} + @param inst: Node object + + """ + ng = ctx.groups.get(node.group, None) + if ng is None: + # Nodes always have a group, or the configuration is corrupt + return (constants.QRFS_UNAVAIL, None) + + return cb(ctx, node, ng) + + return fn + + +def _GetNodeGroup(ctx, node, ng): # pylint: disable-msg=W0613 """Returns the name of a node's group. @type ctx: L{NodeQueryData} @type node: L{objects.Node} @param node: Node object + @type ng: L{objects.NodeGroup} + @param ng: The node group this node belongs to """ - ng = ctx.groups.get(node.group, None) - if ng is None: - # Nodes always have a group, or the configuration is corrupt - return (constants.QRFS_UNAVAIL, None) - return (constants.QRFS_NORMAL, ng.name) @@ -445,6 +500,19 @@ def _GetNodePower(ctx, node): return (constants.QRFS_UNAVAIL, None) +def _GetNdParams(ctx, node, ng): + """Returns the ndparams for this node. + + @type ctx: L{NodeQueryData} + @type node: L{objects.Node} + @param node: Node object + @type ng: L{objects.NodeGroup} + @param ng: The node group this node belongs to + + """ + return (constants.QRFS_NORMAL, ctx.cluster.SimpleFillND(ng.FillND(node))) + + def _GetLiveNodeField(field, kind, ctx, node): """Gets the value of a "live" field from L{NodeQueryData}. @@ -496,11 +564,16 @@ def _BuildNodeFields(): (_MakeField("role", "Role", constants.QFT_TEXT), NQ_CONFIG, lambda ctx, node: (constants.QRFS_NORMAL, _GetNodeRole(node, ctx.master_name))), - (_MakeField("group", "Group", constants.QFT_TEXT), NQ_GROUP, _GetNodeGroup), + (_MakeField("group", "Group", constants.QFT_TEXT), NQ_GROUP, + _GetGroup(_GetNodeGroup)), (_MakeField("group.uuid", "GroupUUID", constants.QFT_TEXT), NQ_CONFIG, lambda ctx, node: (constants.QRFS_NORMAL, node.group)), (_MakeField("powered", "Powered", constants.QFT_BOOL), NQ_OOB, _GetNodePower), + (_MakeField("ndparams", "NodeParameters", constants.QFT_OTHER), NQ_GROUP, + _GetGroup(_GetNdParams)), + (_MakeField("custom_ndparams", "CustomNodeParameters", constants.QFT_OTHER), + NQ_GROUP, lambda ctx, node: (constants.QRFS_NORMAL, node.ndparams)), ] def _GetLength(getter): @@ -1117,6 +1190,7 @@ _GROUP_SIMPLE_FIELDS = { "name": ("Group", constants.QFT_TEXT), "serial_no": ("SerialNo", constants.QFT_NUMBER), "uuid": ("UUID", constants.QFT_TEXT), + "ndparams": ("NDParams", constants.QFT_OTHER), }