diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 289da117ac64f1eec887b332e0f91ddf42ba9493..974cb1f4b810ccf1161898e7bd0dbc4c9612e25e 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -3693,6 +3693,83 @@ class LUQueryNodeStorage(NoHooksLU): return result +def _InstanceQuery(*args): # pylint: disable-msg=W0613 + """Dummy until instance queries have been converted to query2. + + """ + raise NotImplementedError + + +#: Query type implementations +_QUERY_IMPL = { + constants.QR_INSTANCE: _InstanceQuery, + constants.QR_NODE: _NodeQuery, + } + + +def _GetQueryImplementation(name): + """Returns the implemtnation for a query type. + + @param name: Query type, must be one of L{constants.QR_OP_QUERY} + + """ + try: + return _QUERY_IMPL[name] + except KeyError: + raise errors.OpPrereqError("Unknown query resource '%s'" % name, + errors.ECODE_INVAL) + + +class LUQuery(NoHooksLU): + """Query for resources/items of a certain kind. + + """ + # pylint: disable-msg=W0142 + _OP_PARAMS = [ + ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)), + ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString)), + ("filter", None, ht.TOr(ht.TNone, + ht.TListOf(ht.TOr(ht.TNonEmptyString, ht.TList)))), + ] + REQ_BGL = False + + def CheckArguments(self): + qcls = _GetQueryImplementation(self.op.what) + names = qlang.ReadSimpleFilter("name", self.op.filter) + + self.impl = qcls(names, self.op.fields, False) + + def ExpandNames(self): + self.impl.ExpandNames(self) + + def DeclareLocks(self, level): + self.impl.DeclareLocks(self, level) + + def Exec(self, feedback_fn): + return self.impl.NewStyleQuery(self) + + +class LUQueryFields(NoHooksLU): + """Query for resources/items of a certain kind. + + """ + # pylint: disable-msg=W0142 + _OP_PARAMS = [ + ("what", ht.NoDefault, ht.TElemOf(constants.QR_OP_QUERY)), + ("fields", None, ht.TOr(ht.TNone, ht.TListOf(ht.TNonEmptyString))), + ] + REQ_BGL = False + + def CheckArguments(self): + self.qcls = _GetQueryImplementation(self.op.what) + + def ExpandNames(self): + self.needed_locks = {} + + def Exec(self, feedback_fn): + return self.qcls.FieldsQuery(self.op.fields) + + class LUModifyNodeStorage(NoHooksLU): """Logical unit for modifying a storage volume on a node. diff --git a/lib/mcpu.py b/lib/mcpu.py index 277c040b3da1e4ee87d60fc4645193827874367c..1d88f712e083edeed20927888267f34563366fbb 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -154,6 +154,8 @@ class Processor(object): opcodes.OpSetClusterParams: cmdlib.LUSetClusterParams, opcodes.OpRedistributeConfig: cmdlib.LURedistributeConfig, opcodes.OpRepairDiskSizes: cmdlib.LURepairDiskSizes, + opcodes.OpQuery: cmdlib.LUQuery, + opcodes.OpQueryFields: cmdlib.LUQueryFields, # node lu opcodes.OpAddNode: cmdlib.LUAddNode, opcodes.OpQueryNodes: cmdlib.LUQueryNodes, diff --git a/lib/opcodes.py b/lib/opcodes.py index 4587afa82945afb1e66110d8e3f3c875b2917de1..6683425d25cc4d844f60e9797eb5ca68d435aa35 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -330,6 +330,37 @@ class OpRedistributeConfig(OpCode): OP_ID = "OP_CLUSTER_REDIST_CONF" __slots__ = [] + +class OpQuery(OpCode): + """Query for resources/items. + + @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY} + @ivar fields: List of fields to retrieve + @ivar filter: Query filter + + """ + OP_ID = "OP_QUERY" + __slots__ = [ + "what", + "fields", + "filter", + ] + + +class OpQueryFields(OpCode): + """Query for available resource/item fields. + + @ivar what: Resources to query for, must be one of L{constants.QR_OP_QUERY} + @ivar fields: List of fields to retrieve + + """ + OP_ID = "OP_QUERY_FIELDS" + __slots__ = [ + "what", + "fields", + ] + + # node opcodes class OpRemoveNode(OpCode): diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py index 2dc5b5fa19ab1b8bc409897b4e45babd4bd71120..ab2dd868e1a8ae2bb1fb0e8f611326ac25631f38 100755 --- a/test/ganeti.cmdlib_unittest.py +++ b/test/ganeti.cmdlib_unittest.py @@ -28,6 +28,7 @@ import time import tempfile import shutil +from ganeti import constants from ganeti import mcpu from ganeti import cmdlib from ganeti import opcodes @@ -156,5 +157,21 @@ class TestLUTestJobqueue(unittest.TestCase): " in WaitForJobChange")) +class TestLUQuery(unittest.TestCase): + def test(self): + self.assertEqual(sorted(cmdlib._QUERY_IMPL.keys()), + sorted(constants.QR_OP_QUERY)) + + assert constants.QR_NODE in constants.QR_OP_QUERY + assert constants.QR_INSTANCE in constants.QR_OP_QUERY + + for i in constants.QR_OP_QUERY: + self.assert_(cmdlib._GetQueryImplementation(i)) + + self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation, "") + self.assertRaises(errors.OpPrereqError, cmdlib._GetQueryImplementation, + "xyz") + + if __name__ == "__main__": testutils.GanetiTestProgram()