Revision e7c6e02b

b/lib/cmdlib.py
1 1
#
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007 Google Inc.
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
1641 1641
    if not utils.IsValidIP(secondary_ip):
1642 1642
      raise errors.OpPrereqError("Invalid secondary IP given")
1643 1643
    self.op.secondary_ip = secondary_ip
1644

  
1644 1645
    node_list = cfg.GetNodeList()
1645
    if node in node_list:
1646
      raise errors.OpPrereqError("Node %s is already in the configuration"
1647
                                 % node)
1646
    if not self.op.readd and node in node_list:
1647
      raise errors.OpPrereqError("Node %s is already in the configuration" %
1648
                                 node)
1649
    elif self.op.readd and node not in node_list:
1650
      raise errors.OpPrereqError("Node %s is not in the configuration" % node)
1648 1651

  
1649 1652
    for existing_node_name in node_list:
1650 1653
      existing_node = cfg.GetNodeInfo(existing_node_name)
1654

  
1655
      if self.op.readd and node == existing_node_name:
1656
        if (existing_node.primary_ip != primary_ip or
1657
            existing_node.secondary_ip != secondary_ip):
1658
          raise errors.OpPrereqError("Readded node doesn't have the same IP"
1659
                                     " address configuration as before")
1660
        continue
1661

  
1651 1662
      if (existing_node.primary_ip == primary_ip or
1652 1663
          existing_node.secondary_ip == primary_ip or
1653 1664
          existing_node.primary_ip == secondary_ip or
......
1810 1821
      if not self.ssh.CopyFileToNode(node, fname):
1811 1822
        logger.Error("could not copy file %s to node %s" % (fname, node))
1812 1823

  
1813
    logger.Info("adding node %s to cluster.conf" % node)
1814
    self.cfg.AddNode(new_node)
1824
    if not self.op.readd:
1825
      logger.Info("adding node %s to cluster.conf" % node)
1826
      self.cfg.AddNode(new_node)
1815 1827

  
1816 1828

  
1817 1829
class LUMasterFailover(LogicalUnit):
b/lib/opcodes.py
257 257
class OpAddNode(OpCode):
258 258
  """Add a node."""
259 259
  OP_ID = "OP_NODE_ADD"
260
  __slots__ = ["node_name", "primary_ip", "secondary_ip"]
260
  __slots__ = ["node_name", "primary_ip", "secondary_ip", "readd"]
261 261

  
262 262

  
263 263
class OpQueryNodes(OpCode):
b/man/gnt-node.sgml
20 20
    <copyright>
21 21
      <year>2006</year>
22 22
      <year>2007</year>
23
      <year>2008</year>
23 24
      <holder>Google Inc.</holder>
24 25
    </copyright>
25 26
    &dhdate;
......
60 61

  
61 62
      <cmdsynopsis>
62 63
        <command>add</command>
64
        <arg>--readd</arg>
63 65
        <arg>-s <replaceable>secondary_ip</replaceable></arg>
64 66
        <arg choice="req"><replaceable>nodename</replaceable></arg>
65 67
      </cmdsynopsis>
......
92 94
      </para>
93 95

  
94 96
      <para>
97
        In case you're readding a node after hardware failure, you
98
        can use the <option>--readd</option> parameter.
99
      </para>
100

  
101
      <para>
95 102
        Example:
96 103
        <screen>
97 104
# gnt-node add node5.example.com
b/qa/ganeti-qa.py
263 263
    if qa_config.TestEnabled('tags'):
264 264
      RunTest(qa_tags.TestNodeTags, pnode)
265 265

  
266
    if qa_config.TestEnabled('node-readd'):
267
      RunTest(qa_node.TestNodeReadd, pnode)
268

  
266 269
    if qa_config.TestEnabled('instance-add-plain-disk'):
267 270
      instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, pnode)
268 271
      RunCommonInstanceTests(instance)
b/qa/qa-sample.yaml
41 41

  
42 42
  node-info: True
43 43
  node-volumes: True
44
  node-readd: True
44 45

  
45 46
  # This test needs at least three nodes
46 47
  node-evacuate: False
b/qa/qa_node.py
29 29

  
30 30

  
31 31
@qa_utils.DefineHook('node-add')
32
def _NodeAdd(node):
32
def _NodeAdd(node, readd=False):
33 33
  master = qa_config.GetMasterNode()
34 34

  
35
  if node.get('_added', False):
35
  if not readd and node.get('_added', False):
36 36
    raise qa_error.Error("Node %s already in cluster" % node['primary'])
37
  elif readd and not node.get('_added', False):
38
    raise qa_error.Error("Node not yet %s in cluster" % node['primary'])
37 39

  
38 40
  cmd = ['gnt-node', 'add']
39 41
  if node.get('secondary', None):
40 42
    cmd.append('--secondary-ip=%s' % node['secondary'])
43
  if readd:
44
    cmd.append('--readd')
41 45
  cmd.append(node['primary'])
42 46
  AssertEqual(StartSSH(master['primary'],
43 47
                       utils.ShellQuoteArgs(cmd)).wait(), 0)
......
60 64
  master = qa_config.GetMasterNode()
61 65
  for node in qa_config.get('nodes'):
62 66
    if node != master:
63
      _NodeAdd(node)
67
      _NodeAdd(node, readd=False)
64 68

  
65 69

  
66 70
def TestNodeRemoveAll():
......
71 75
      _NodeRemove(node)
72 76

  
73 77

  
78
@qa_utils.DefineHook('node-readd')
79
def TestNodeReadd(node):
80
  """gnt-node add --readd"""
81
  _NodeAdd(node, readd=True)
82

  
83

  
74 84
@qa_utils.DefineHook('node-info')
75 85
def TestNodeInfo():
76 86
  """gnt-node info"""
b/scripts/gnt-node
1 1
#!/usr/bin/python
2 2
#
3 3

  
4
# Copyright (C) 2006, 2007 Google Inc.
4
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 5
#
6 6
# This program is free software; you can redistribute it and/or modify
7 7
# it under the terms of the GNU General Public License as published by
......
36 36
    "Performing this operation is going to replace the ssh daemon keypair\n"
37 37
    "on the target machine (%s) with the ones of the current one\n"
38 38
    "and grant full intra-cluster ssh root access to/from it\n" % args[0])
39
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip)
39
  op = opcodes.OpAddNode(node_name=args[0], secondary_ip=opts.secondary_ip,
40
                         readd=opts.readd)
40 41
  SubmitOpCode(op)
41 42

  
42 43

  
......
279 280
          [DEBUG_OPT,
280 281
           make_option("-s", "--secondary-ip", dest="secondary_ip",
281 282
                       help="Specify the secondary ip for the node",
282
                       metavar="ADDRESS", default=None),],
283
                       metavar="ADDRESS", default=None),
284
           make_option("--readd", dest="readd",
285
                       default=False, action="store_true",
286
                       help="Readd old node after replacing it"),
287
           ],
283 288
          "[-s ip] <node_name>", "Add a node to the cluster"),
284 289
  'evacuate': (EvacuateNode, ARGS_FIXED(2),
285 290
               [DEBUG_OPT, FORCE_OPT],

Also available in: Unified diff