diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 5d18c2f7b908c66e0d2c796ee88af8c0e68b7f8f..873f216db95eda146ce9c1134dbe951db2dfbbfd 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1,7 +1,7 @@
 #
 #
 
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2008 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
@@ -1641,13 +1641,24 @@ class LUAddNode(LogicalUnit):
     if not utils.IsValidIP(secondary_ip):
       raise errors.OpPrereqError("Invalid secondary IP given")
     self.op.secondary_ip = secondary_ip
+
     node_list = cfg.GetNodeList()
-    if node in node_list:
-      raise errors.OpPrereqError("Node %s is already in the configuration"
-                                 % node)
+    if not self.op.readd and node in node_list:
+      raise errors.OpPrereqError("Node %s is already in the configuration" %
+                                 node)
+    elif self.op.readd and node not in node_list:
+      raise errors.OpPrereqError("Node %s is not in the configuration" % node)
 
     for existing_node_name in node_list:
       existing_node = cfg.GetNodeInfo(existing_node_name)
+
+      if self.op.readd and node == existing_node_name:
+        if (existing_node.primary_ip != primary_ip or
+            existing_node.secondary_ip != secondary_ip):
+          raise errors.OpPrereqError("Readded node doesn't have the same IP"
+                                     " address configuration as before")
+        continue
+
       if (existing_node.primary_ip == primary_ip or
           existing_node.secondary_ip == primary_ip or
           existing_node.primary_ip == secondary_ip or
@@ -1810,8 +1821,9 @@ class LUAddNode(LogicalUnit):
       if not self.ssh.CopyFileToNode(node, fname):
         logger.Error("could not copy file %s to node %s" % (fname, node))
 
-    logger.Info("adding node %s to cluster.conf" % node)
-    self.cfg.AddNode(new_node)
+    if not self.op.readd:
+      logger.Info("adding node %s to cluster.conf" % node)
+      self.cfg.AddNode(new_node)
 
 
 class LUMasterFailover(LogicalUnit):
diff --git a/lib/opcodes.py b/lib/opcodes.py
index 117757f9f2896889d858a41c7c092db3f4003f6b..c629e0c91a43ad4e781eabbc3cc2afaf11c0a98e 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -257,7 +257,7 @@ class OpRemoveNode(OpCode):
 class OpAddNode(OpCode):
   """Add a node."""
   OP_ID = "OP_NODE_ADD"
-  __slots__ = ["node_name", "primary_ip", "secondary_ip"]
+  __slots__ = ["node_name", "primary_ip", "secondary_ip", "readd"]
 
 
 class OpQueryNodes(OpCode):
diff --git a/man/gnt-node.sgml b/man/gnt-node.sgml
index 98ec3437a41015b78820739db56bfc86d78d6a6d..71f9dbfc3130e1052ee80c5a78fe7ac12a97b9a9 100644
--- a/man/gnt-node.sgml
+++ b/man/gnt-node.sgml
@@ -20,6 +20,7 @@
     <copyright>
       <year>2006</year>
       <year>2007</year>
+      <year>2008</year>
       <holder>Google Inc.</holder>
     </copyright>
     &dhdate;
@@ -60,6 +61,7 @@
 
       <cmdsynopsis>
         <command>add</command>
+        <arg>--readd</arg>
         <arg>-s <replaceable>secondary_ip</replaceable></arg>
         <arg choice="req"><replaceable>nodename</replaceable></arg>
       </cmdsynopsis>
@@ -91,6 +93,11 @@
         informations.
       </para>
 
+      <para>
+        In case you're readding a node after hardware failure, you
+        can use the <option>--readd</option> parameter.
+      </para>
+
       <para>
         Example:
         <screen>
diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py
index 01614e0246cc2ad5c21d36670b4219a61fc6abe6..47db0b79006901abb4297765125833d2c6504276 100755
--- a/qa/ganeti-qa.py
+++ b/qa/ganeti-qa.py
@@ -263,6 +263,9 @@ def main():
     if qa_config.TestEnabled('tags'):
       RunTest(qa_tags.TestNodeTags, pnode)
 
+    if qa_config.TestEnabled('node-readd'):
+      RunTest(qa_node.TestNodeReadd, pnode)
+
     if qa_config.TestEnabled('instance-add-plain-disk'):
       instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
       RunCommonInstanceTests(instance)
diff --git a/qa/qa-sample.yaml b/qa/qa-sample.yaml
index c4aedf9843413ed132a64856cd874d8b2c10580e..4138ea242e7ad3402b1a79ef745466b09efe06f0 100644
--- a/qa/qa-sample.yaml
+++ b/qa/qa-sample.yaml
@@ -41,6 +41,7 @@ tests:
 
   node-info: True
   node-volumes: True
+  node-readd: True
 
   # This test needs at least three nodes
   node-evacuate: False
diff --git a/qa/qa_node.py b/qa/qa_node.py
index 26eccebceee635bbc71c5483cba0e62a9530e1bd..20840bde1c859a1accf13909d788579df5da481a 100644
--- a/qa/qa_node.py
+++ b/qa/qa_node.py
@@ -29,15 +29,19 @@ from qa_utils import AssertEqual, StartSSH
 
 
 @qa_utils.DefineHook('node-add')
-def _NodeAdd(node):
+def _NodeAdd(node, readd=False):
   master = qa_config.GetMasterNode()
 
-  if node.get('_added', False):
+  if not readd and node.get('_added', False):
     raise qa_error.Error("Node %s already in cluster" % node['primary'])
+  elif readd and not node.get('_added', False):
+    raise qa_error.Error("Node not yet %s in cluster" % node['primary'])
 
   cmd = ['gnt-node', 'add']
   if node.get('secondary', None):
     cmd.append('--secondary-ip=%s' % node['secondary'])
+  if readd:
+    cmd.append('--readd')
   cmd.append(node['primary'])
   AssertEqual(StartSSH(master['primary'],
                        utils.ShellQuoteArgs(cmd)).wait(), 0)
@@ -60,7 +64,7 @@ def TestNodeAddAll():
   master = qa_config.GetMasterNode()
   for node in qa_config.get('nodes'):
     if node != master:
-      _NodeAdd(node)
+      _NodeAdd(node, readd=False)
 
 
 def TestNodeRemoveAll():
@@ -71,6 +75,12 @@ def TestNodeRemoveAll():
       _NodeRemove(node)
 
 
+@qa_utils.DefineHook('node-readd')
+def TestNodeReadd(node):
+  """gnt-node add --readd"""
+  _NodeAdd(node, readd=True)
+
+
 @qa_utils.DefineHook('node-info')
 def TestNodeInfo():
   """gnt-node info"""
diff --git a/scripts/gnt-node b/scripts/gnt-node
index 442d8f232f5d5767a5de2ea0b11b755285e2bd2e..c8082c9019bbae34d1c3eab2d8e7954999eac623 100755
--- a/scripts/gnt-node
+++ b/scripts/gnt-node
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2006, 2007 Google Inc.
+# Copyright (C) 2006, 2007, 2008 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
@@ -36,7 +36,8 @@ def AddNode(opts, args):
     "Performing this operation is going to replace the ssh daemon keypair\n"
     "on the target machine (%s) with the ones of the current one\n"
     "and grant full intra-cluster ssh root access to/from it\n" % args[0])
-  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip)
+  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
+                         readd=opts.readd)
   SubmitOpCode(op)
 
 
@@ -279,7 +280,11 @@ commands = {
           [DEBUG_OPT,
            make_option("-s", "--secondary-ip", dest="secondary_ip",
                        help="Specify the secondary ip for the node",
-                       metavar="ADDRESS", default=None),],
+                       metavar="ADDRESS", default=None),
+           make_option("--readd", dest="readd",
+                       default=False, action="store_true",
+                       help="Readd old node after replacing it"),
+           ],
           "[-s ip] <node_name>", "Add a node to the cluster"),
   'evacuate': (EvacuateNode, ARGS_FIXED(2),
                [DEBUG_OPT, FORCE_OPT],