diff --git a/Makefile.am b/Makefile.am
index e6217ae53b11f0a9c89de8e6408cfbe7f2b80bf1..d891a6d4b8d58568b45bf85bf3c75315f39ac993 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -540,6 +540,7 @@ HS_LIB_SRCS = \
 	src/Ganeti/OpParams.hs \
 	src/Ganeti/Path.hs \
 	src/Ganeti/Query/Common.hs \
+	src/Ganeti/Query/Export.hs \
 	src/Ganeti/Query/Filter.hs \
 	src/Ganeti/Query/Group.hs \
 	src/Ganeti/Query/Job.hs \
diff --git a/src/Ganeti/Query/Export.hs b/src/Ganeti/Query/Export.hs
new file mode 100644
index 0000000000000000000000000000000000000000..6a9671b97a0070521d37ecf0e2599b3ef1965f3a
--- /dev/null
+++ b/src/Ganeti/Query/Export.hs
@@ -0,0 +1,81 @@
+{-| Implementation of the Ganeti Query2 export queries.
+
+ -}
+
+{-
+
+Copyright (C) 2013 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
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Ganeti.Query.Export
+  ( Runtime
+  , fieldsMap
+  , collectLiveData
+  ) where
+
+import Control.Monad (liftM)
+import qualified Data.Map as Map
+
+import Ganeti.Objects
+import Ganeti.Rpc
+import Ganeti.Query.Language
+import Ganeti.Query.Common
+import Ganeti.Query.Types
+
+-- | The parsed result of the ExportList. This is a bit tricky, in
+-- that we already do parsing of the results in the RPC calls, so the
+-- runtime type is a plain 'ResultEntry', as we have just one type.
+type Runtime = ResultEntry
+
+-- | Small helper for rpc to rs.
+rpcErrToRs :: RpcError -> ResultEntry
+rpcErrToRs err = ResultEntry (rpcErrorToStatus err) Nothing
+
+-- | Helper for extracting fields from RPC result.
+rpcExtractor :: Node -> Either RpcError RpcResultExportList
+             -> [(Node, ResultEntry)]
+rpcExtractor node (Right res) =
+  [(node, rsNormal path) | path <- rpcResExportListExports res]
+rpcExtractor node (Left err)  = [(node, rpcErrToRs err)]
+
+-- | List of all node fields.
+exportFields :: FieldList Node Runtime
+exportFields =
+  [ (FieldDefinition "node" "Node" QFTText "Node name",
+     FieldSimple (rsNormal . nodeName), QffNormal)
+  , (FieldDefinition "export" "Export" QFTText "Export name",
+     FieldRuntime (curry fst), QffNormal)
+  ]
+
+-- | The node fields map.
+fieldsMap :: FieldMap Node Runtime
+fieldsMap =
+  Map.fromList $ map (\v@(f, _, _) -> (fdefName f, v)) exportFields
+
+-- | Collect live data from RPC query if enabled.
+--
+-- Note that this function is \"funny\": the returned rows will not be
+-- 1:1 with the input, as nodes without exports will be pruned,
+-- whereas nodes with multiple exports will be listed multiple times.
+collectLiveData:: Bool -> ConfigData -> [Node] -> IO [(Node, Runtime)]
+collectLiveData False _ nodes =
+  return [(n, rpcErrToRs $ RpcResultError "Live data disabled") | n <- nodes]
+collectLiveData True _ nodes =
+  concatMap (uncurry rpcExtractor) `liftM`
+    executeRpcCall nodes RpcCallExportList
diff --git a/src/Ganeti/Query/Query.hs b/src/Ganeti/Query/Query.hs
index 515d6d4dac9a970c3f7107fc91dc4c4132c5738c..3e5d7ec9e9800dc4f742a6ee4ffcc9ef8e955d24 100644
--- a/src/Ganeti/Query/Query.hs
+++ b/src/Ganeti/Query/Query.hs
@@ -4,7 +4,7 @@
 
 {-
 
-Copyright (C) 2012 Google Inc.
+Copyright (C) 2012, 2013 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
@@ -67,6 +67,7 @@ import Ganeti.JQueue
 import Ganeti.JSON
 import Ganeti.Objects
 import Ganeti.Query.Common
+import qualified Ganeti.Query.Export as Export
 import Ganeti.Query.Filter
 import qualified Ganeti.Query.Job as Query.Job
 import Ganeti.Query.Group
@@ -117,6 +118,7 @@ needsNames (Query kind _ qfilter) = requestedNames (nameField kind) qfilter
 -- | Computes the name field for different query types.
 nameField :: ItemType -> FilterField
 nameField (ItemTypeLuxi QRJob) = "id"
+nameField (ItemTypeOpCode QRExport) = "node"
 nameField _ = "name"
 
 -- | Extracts all quoted strings from a list, ignoring the
@@ -215,6 +217,31 @@ queryInner cfg _ (Query (ItemTypeOpCode QRNetwork) fields qfilter) wanted =
                    fnetworks
   return QueryResult { qresFields = fdefs, qresData = fdata }
 
+queryInner cfg live (Query (ItemTypeOpCode QRExport) fields qfilter) wanted =
+  runResultT $ do
+  cfilter <- resultT $ compileFilter Export.fieldsMap qfilter
+  let selected = getSelectedFields Export.fieldsMap fields
+      (fdefs, fgetters, _) = unzip3 selected
+      -- we alwyas have live queries in exports, but we keep this for
+      -- standard style (in case we add static fields in the future)
+      live' = live && needsLiveData fgetters
+  nodes <- resultT $ case wanted of
+             [] -> Ok . niceSortKey nodeName .
+                   Map.elems . fromContainer $ configNodes cfg
+             _  -> mapM (getNode cfg) wanted
+  -- runs first pass of the filter, without a runtime context; this
+  -- will limit the nodes that we'll contact for exports
+  fnodes <- resultT $ filterM (\n -> evaluateFilter cfg Nothing n cfilter)
+                      nodes
+  -- here we would run the runtime data gathering...
+  nruntimes <- lift $ Export.collectLiveData live' cfg fnodes
+  -- ... then filter again the results, based on existing export
+  -- names, but note that no client sends filters on the export list
+  -- today, so it's likely a no-oop
+  let fdata = map (\(node, nrt) -> map (execGetter cfg nrt node) fgetters)
+              nruntimes
+  return QueryResult { qresFields = fdefs, qresData = fdata }
+
 queryInner _ _ (Query qkind _ _) _ =
   return . Bad . GenericError $ "Query '" ++ show qkind ++ "' not supported"
 
@@ -289,6 +316,9 @@ queryFields (QueryFields (ItemTypeOpCode QRGroup) fields) =
 queryFields (QueryFields (ItemTypeLuxi QRJob) fields) =
   Ok $ fieldsExtractor Query.Job.fieldsMap fields
 
+queryFields (QueryFields (ItemTypeOpCode QRExport) fields) =
+  Ok $ fieldsExtractor Export.fieldsMap fields
+
 queryFields (QueryFields qkind _) =
   Bad . GenericError $ "QueryFields '" ++ show qkind ++ "' not supported"