Revision 7e9366f7

b/lib/cmdlib.py
4255 4255
  _OP_REQP = ["instance_name", "mode", "disks"]
4256 4256
  REQ_BGL = False
4257 4257

  
4258
  def ExpandNames(self):
4259
    self._ExpandAndLockInstance()
4260

  
4258
  def CheckArguments(self):
4261 4259
    if not hasattr(self.op, "remote_node"):
4262 4260
      self.op.remote_node = None
4263

  
4264
    ia_name = getattr(self.op, "iallocator", None)
4265
    if ia_name is not None:
4266
      if self.op.remote_node is not None:
4261
    if not hasattr(self.op, "iallocator"):
4262
      self.op.iallocator = None
4263

  
4264
    # check for valid parameter combination
4265
    cnt = [self.op.remote_node, self.op.iallocator].count(None)
4266
    if self.op.mode == constants.REPLACE_DISK_CHG:
4267
      if cnt == 2:
4268
        raise errors.OpPrereqError("When changing the secondary either an"
4269
                                   " iallocator script must be used or the"
4270
                                   " new node given")
4271
      elif cnt == 0:
4267 4272
        raise errors.OpPrereqError("Give either the iallocator or the new"
4268 4273
                                   " secondary, not both")
4274
    else: # not replacing the secondary
4275
      if cnt != 2:
4276
        raise errors.OpPrereqError("The iallocator and new node options can"
4277
                                   " be used only when changing the"
4278
                                   " secondary node")
4279

  
4280
  def ExpandNames(self):
4281
    self._ExpandAndLockInstance()
4282

  
4283
    if self.op.iallocator is not None:
4269 4284
      self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
4270 4285
    elif self.op.remote_node is not None:
4271 4286
      remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
......
4340 4355
      "Cannot retrieve locked instance %s" % self.op.instance_name
4341 4356
    self.instance = instance
4342 4357

  
4343
    if instance.disk_template not in constants.DTS_NET_MIRROR:
4344
      raise errors.OpPrereqError("Instance's disk layout is not"
4345
                                 " network mirrored.")
4358
    if instance.disk_template != constants.DT_DRBD8:
4359
      raise errors.OpPrereqError("Can only run replace disks for DRBD8-based"
4360
                                 " instances")
4346 4361

  
4347 4362
    if len(instance.secondary_nodes) != 1:
4348 4363
      raise errors.OpPrereqError("The instance has a strange layout,"
......
4351 4366

  
4352 4367
    self.sec_node = instance.secondary_nodes[0]
4353 4368

  
4354
    ia_name = getattr(self.op, "iallocator", None)
4355
    if ia_name is not None:
4369
    if self.op.iallocator is not None:
4356 4370
      self._RunAllocator()
4357 4371

  
4358 4372
    remote_node = self.op.remote_node
......
4366 4380
      raise errors.OpPrereqError("The specified node is the primary node of"
4367 4381
                                 " the instance.")
4368 4382
    elif remote_node == self.sec_node:
4369
      if self.op.mode == constants.REPLACE_DISK_SEC:
4370
        # this is for DRBD8, where we can't execute the same mode of
4371
        # replacement as for drbd7 (no different port allocated)
4372
        raise errors.OpPrereqError("Same secondary given, cannot execute"
4373
                                   " replacement")
4374
    if instance.disk_template == constants.DT_DRBD8:
4375
      if (self.op.mode == constants.REPLACE_DISK_ALL and
4376
          remote_node is not None):
4377
        # switch to replace secondary mode
4378
        self.op.mode = constants.REPLACE_DISK_SEC
4379

  
4380
      if self.op.mode == constants.REPLACE_DISK_ALL:
4381
        raise errors.OpPrereqError("Template 'drbd' only allows primary or"
4382
                                   " secondary disk replacement, not"
4383
                                   " both at once")
4384
      elif self.op.mode == constants.REPLACE_DISK_PRI:
4385
        if remote_node is not None:
4386
          raise errors.OpPrereqError("Template 'drbd' does not allow changing"
4387
                                     " the secondary while doing a primary"
4388
                                     " node disk replacement")
4389
        self.tgt_node = instance.primary_node
4390
        self.oth_node = instance.secondary_nodes[0]
4391
        _CheckNodeOnline(self, self.tgt_node)
4392
        _CheckNodeOnline(self, self.oth_node)
4393
      elif self.op.mode == constants.REPLACE_DISK_SEC:
4394
        self.new_node = remote_node # this can be None, in which case
4395
                                    # we don't change the secondary
4396
        self.tgt_node = instance.secondary_nodes[0]
4397
        self.oth_node = instance.primary_node
4398
        _CheckNodeOnline(self, self.oth_node)
4399
        if self.new_node is not None:
4400
          _CheckNodeOnline(self, self.new_node)
4401
        else:
4402
          _CheckNodeOnline(self, self.tgt_node)
4403
      else:
4404
        raise errors.ProgrammerError("Unhandled disk replace mode")
4383
      raise errors.OpPrereqError("The specified node is already the"
4384
                                 " secondary node of the instance.")
4385

  
4386
    if self.op.mode == constants.REPLACE_DISK_PRI:
4387
      n1 = self.tgt_node = instance.primary_node
4388
      n2 = self.oth_node = self.sec_node
4389
    elif self.op.mode == constants.REPLACE_DISK_SEC:
4390
      n1 = self.tgt_node = self.sec_node
4391
      n2 = self.oth_node = instance.primary_node
4392
    elif self.op.mode == constants.REPLACE_DISK_CHG:
4393
      n1 = self.new_node = remote_node
4394
      n2 = self.oth_node = instance.primary_node
4395
      self.tgt_node = self.sec_node
4396
    else:
4397
      raise errors.ProgrammerError("Unhandled disk replace mode")
4398

  
4399
    _CheckNodeOnline(self, n1)
4400
    _CheckNodeOnline(self, n2)
4405 4401

  
4406 4402
    if not self.op.disks:
4407 4403
      self.op.disks = range(len(instance.disks))
......
4793 4789
    if instance.status == "down":
4794 4790
      _StartInstanceDisks(self, instance, True)
4795 4791

  
4796
    if instance.disk_template == constants.DT_DRBD8:
4797
      if self.op.remote_node is None:
4798
        fn = self._ExecD8DiskOnly
4799
      else:
4800
        fn = self._ExecD8Secondary
4792
    if self.op.mode == constants.REPLACE_DISK_CHG:
4793
      fn = self._ExecD8Secondary
4801 4794
    else:
4802
      raise errors.ProgrammerError("Unhandled disk replacement case")
4795
      fn = self._ExecD8DiskOnly
4803 4796

  
4804 4797
    ret = fn(feedback_fn)
4805 4798

  
b/lib/constants.py
193 193
DISK_ACCESS_SET = frozenset([DISK_RDONLY, DISK_RDWR])
194 194

  
195 195
# disk replacement mode
196
REPLACE_DISK_PRI = "replace_primary"
197
REPLACE_DISK_SEC = "replace_secondary"
198
REPLACE_DISK_ALL = "replace_all"
196
REPLACE_DISK_PRI = "replace_primary"   # replace disks on primary
197
REPLACE_DISK_SEC = "replace_secondary" # replace disks on secondary
198
REPLACE_DISK_CHG = "replace_all"       # change secondary node
199 199

  
200 200
# lock recalculate mode
201 201
LOCKS_REPLACE = 'replace'
b/man/gnt-instance.sgml
1082 1082

  
1083 1083
        <cmdsynopsis>
1084 1084
          <command>replace-disks</command>
1085
          <arg choice="req">-p</arg>
1086
          <arg choice="req"><replaceable>instance</replaceable></arg>
1087
        </cmdsynopsis>
1085 1088

  
1086
          <group choice="req">
1087
            <arg>--iallocator <replaceable>name</replaceable></arg>
1088
            <arg>--new-secondary <replaceable>NODE</replaceable></arg>
1089
          </group>
1090
          <sbr>
1089
        <cmdsynopsis>
1090
          <command>replace-disks</command>
1091 1091

  
1092
          <arg choice="opt">-s</arg>
1092
          <arg choice="req">-s</arg>
1093 1093
          <arg choice="req"><replaceable>instance</replaceable></arg>
1094 1094
        </cmdsynopsis>
1095 1095

  
1096 1096
        <cmdsynopsis>
1097 1097
          <command>replace-disks</command>
1098 1098

  
1099
          <group>
1100
          <arg choice="req">-s</arg>
1101
          <arg choice="req">-p</arg>
1099
          <group choice="req">
1100
            <arg>--iallocator <replaceable>name</replaceable></arg>
1101
            <arg>--new-secondary <replaceable>NODE</replaceable></arg>
1102 1102
          </group>
1103

  
1103 1104
          <arg choice="req"><replaceable>instance</replaceable></arg>
1104 1105
        </cmdsynopsis>
1105 1106

  
......
1110 1111
        </para>
1111 1112

  
1112 1113
        <para>
1113
          The first form will do a secondary node change, while the
1114
          second form will replace the disks on either the primary
1115
          (<option>-p</option>) or the secondary (<option>-s</option>)
1116
          node of the instance only, without changing the node.
1114
          The first form (when passing the <option>-p</option> option)
1115
          will replace the disks on the primary, while the second form
1116
          (when passing the <option>-s</option> option will replace
1117
          the disks on the secondary node.
1117 1118
        </para>
1118 1119

  
1119 1120
        <para>
1120
          Specifying <option>--iallocator</option> enables secondary node
1121
          replacement and and makes the new secondary be selected automatically
1122
          by the specified allocator plugin.
1121
          The third form (when passing either the
1122
          <option>--iallocator</option> or the
1123
          <option>--new-secondary</option> option) is designed to
1124
          change secondary node of the instance.  Specifying
1125
          <option>--iallocator</option> makes the new secondary be
1126
          selected automatically by the specified allocator plugin,
1127
          otherwise the new secondary node will be the one chosen
1128
          manually via the <option>--new-secondary</option> option.
1123 1129
        </para>
1124 1130
      </refsect3>
1125 1131

  
b/scripts/gnt-instance
772 772
      disks = [int(i) for i in opts.disks.split(",")]
773 773
    except ValueError, err:
774 774
      raise errors.OpPrereqError("Invalid disk index passed: %s" % str(err))
775
  if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
776
    mode = constants.REPLACE_DISK_ALL
777
  elif opts.on_primary: # only on primary:
775
  cnt = [opts.on_primary, opts.on_secondary,
776
         new_2ndary is not None, iallocator is not None].count(True)
777
  if cnt != 1:
778
    raise errors.OpPrereqError("One and only one of the -p, -s, -n and -i"
779
                               " options must be passed")
780
  elif opts.on_primary:
778 781
    mode = constants.REPLACE_DISK_PRI
779
    if new_2ndary is not None or iallocator is not None:
780
      raise errors.OpPrereqError("Can't change secondary node on primary disk"
781
                                 " replacement")
782
  elif opts.on_secondary is not None or iallocator is not None:
783
    # only on secondary
782
  elif opts.on_secondary:
784 783
    mode = constants.REPLACE_DISK_SEC
784
  elif new_2ndary is not None or iallocator is not None:
785
    # replace secondary
786
    mode = constants.REPLACE_DISK_CHG
785 787

  
786 788
  op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
787 789
                              remote_node=new_2ndary, mode=mode,
......
1254 1256
                    [DEBUG_OPT,
1255 1257
                     make_option("-n", "--new-secondary", dest="new_secondary",
1256 1258
                                 help=("New secondary node (for secondary"
1257
                                       " node change)"), metavar="NODE"),
1259
                                       " node change)"), metavar="NODE",
1260
                                 default=None),
1258 1261
                     make_option("-p", "--on-primary", dest="on_primary",
1259 1262
                                 default=False, action="store_true",
1260 1263
                                 help=("Replace the disk(s) on the primary"
......
1267 1270
                                 help=("Comma-separated list of disks"
1268 1271
                                       " to replace (e.g. sda) (optional,"
1269 1272
                                       " defaults to all disks")),
1270
                     make_option("--iallocator", metavar="<NAME>",
1273
                     make_option("-i", "--iallocator", metavar="<NAME>",
1271 1274
                                 help="Select new secondary for the instance"
1272 1275
                                 " automatically using the"
1273 1276
                                 " <NAME> iallocator plugin (enables"

Also available in: Unified diff