diff --git a/lib/objects.py b/lib/objects.py
index fc077b38e213bc4639eb5354d08216fd65cb9a9b..0a15e98dae55525cbdf7493307ce279ee9e2f18f 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -989,6 +989,40 @@ class OS(ConfigObject):
     return cls.SplitNameVariant(name)[1]
 
 
+class NodeHvState(ConfigObject):
+  """Hypvervisor state on a node.
+
+  @ivar mem_total: Total amount of memory
+  @ivar mem_node: Memory used by, or reserved for, the node itself (not always
+    available)
+  @ivar mem_hv: Memory used by hypervisor or lost due to instance allocation
+    rounding
+  @ivar mem_inst: Memory used by instances living on node
+  @ivar cpu_total: Total node CPU core count
+  @ivar cpu_node: Number of CPU cores reserved for the node itself
+
+  """
+  __slots__ = [
+    "mem_total",
+    "mem_node",
+    "mem_hv",
+    "mem_inst",
+    "cpu_total",
+    "cpu_node",
+    ] + _TIMESTAMPS
+
+
+class NodeDiskState(ConfigObject):
+  """Disk state on a node.
+
+  """
+  __slots__ = [
+    "total",
+    "reserved",
+    "overhead",
+    ] + _TIMESTAMPS
+
+
 class Node(TaggableObject):
   """Config object representing a node.
 
@@ -1035,6 +1069,41 @@ class Node(TaggableObject):
     if self.powered is None:
       self.powered = True
 
+  def ToDict(self):
+    """Custom function for serializing.
+
+    """
+    data = super(Node, self).ToDict()
+
+    hv_state = data.get("hv_state", None)
+    if hv_state is not None:
+      data["hv_state"] = self._ContainerToDicts(hv_state)
+
+    disk_state = data.get("disk_state", None)
+    if disk_state is not None:
+      data["disk_state"] = \
+        dict((key, self._ContainerToDicts(value))
+             for (key, value) in disk_state.items())
+
+    return data
+
+  @classmethod
+  def FromDict(cls, val):
+    """Custom function for deserializing.
+
+    """
+    obj = super(Node, cls).FromDict(val)
+
+    if obj.hv_state is not None:
+      obj.hv_state = cls._ContainerFromDicts(obj.hv_state, dict, NodeHvState)
+
+    if obj.disk_state is not None:
+      obj.disk_state = \
+        dict((key, cls._ContainerFromDicts(value, dict, NodeDiskState))
+             for (key, value) in obj.disk_state.items())
+
+    return obj
+
 
 class NodeGroup(TaggableObject):
   """Config object representing a node group."""
diff --git a/test/ganeti.objects_unittest.py b/test/ganeti.objects_unittest.py
index 23f2e28b0ca57f20c75829913e5174b623f616cb..20b63f1ba5f04bd3b163a29150d702c1151ad79e 100755
--- a/test/ganeti.objects_unittest.py
+++ b/test/ganeti.objects_unittest.py
@@ -283,5 +283,54 @@ class TestInstance(unittest.TestCase):
     self.assertRaises(errors.OpPrereqError, inst.FindDisk, 1)
 
 
+class TestNode(unittest.TestCase):
+  def testEmpty(self):
+    self.assertEqual(objects.Node().ToDict(), {})
+    self.assertTrue(isinstance(objects.Node.FromDict({}), objects.Node))
+
+  def testHvState(self):
+    node = objects.Node(name="node18157.example.com", hv_state={
+      constants.HT_XEN_HVM: objects.NodeHvState(cpu_total=64),
+      constants.HT_KVM: objects.NodeHvState(cpu_node=1),
+      })
+
+    node2 = objects.Node.FromDict(node.ToDict())
+
+    # Make sure nothing can reference it anymore
+    del node
+
+    self.assertEqual(node2.name, "node18157.example.com")
+    self.assertEqual(frozenset(node2.hv_state), frozenset([
+      constants.HT_XEN_HVM,
+      constants.HT_KVM,
+      ]))
+    self.assertEqual(node2.hv_state[constants.HT_KVM].cpu_node, 1)
+    self.assertEqual(node2.hv_state[constants.HT_XEN_HVM].cpu_total, 64)
+
+  def testDiskState(self):
+    node = objects.Node(name="node32087.example.com", disk_state={
+      constants.LD_LV: {
+        "lv32352": objects.NodeDiskState(total=128),
+        "lv2082": objects.NodeDiskState(total=512),
+        },
+      })
+
+    node2 = objects.Node.FromDict(node.ToDict())
+
+    # Make sure nothing can reference it anymore
+    del node
+
+    self.assertEqual(node2.name, "node32087.example.com")
+    self.assertEqual(frozenset(node2.disk_state), frozenset([
+      constants.LD_LV,
+      ]))
+    self.assertEqual(frozenset(node2.disk_state[constants.LD_LV]), frozenset([
+      "lv32352",
+      "lv2082",
+      ]))
+    self.assertEqual(node2.disk_state[constants.LD_LV]["lv2082"].total, 512)
+    self.assertEqual(node2.disk_state[constants.LD_LV]["lv32352"].total, 128)
+
+
 if __name__ == '__main__':
   testutils.GanetiTestProgram()