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()