Revision 249069a1

b/lib/cmdlib.py
3203 3203
    return cmd[0], cmd
3204 3204

  
3205 3205

  
3206
class LUAddMDDRBDComponent(LogicalUnit):
3207
  """Adda new mirror member to an instance's disk.
3208

  
3209
  """
3210
  HPATH = "mirror-add"
3211
  HTYPE = constants.HTYPE_INSTANCE
3212
  _OP_REQP = ["instance_name", "remote_node", "disk_name"]
3213

  
3214
  def BuildHooksEnv(self):
3215
    """Build hooks env.
3216

  
3217
    This runs on the master, the primary and all the secondaries.
3218

  
3219
    """
3220
    env = {
3221
      "NEW_SECONDARY": self.op.remote_node,
3222
      "DISK_NAME": self.op.disk_name,
3223
      }
3224
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3225
    nl = [self.sstore.GetMasterNode(), self.instance.primary_node,
3226
          self.op.remote_node,] + list(self.instance.secondary_nodes)
3227
    return env, nl, nl
3228

  
3229
  def CheckPrereq(self):
3230
    """Check prerequisites.
3231

  
3232
    This checks that the instance is in the cluster.
3233

  
3234
    """
3235
    instance = self.cfg.GetInstanceInfo(
3236
      self.cfg.ExpandInstanceName(self.op.instance_name))
3237
    if instance is None:
3238
      raise errors.OpPrereqError("Instance '%s' not known" %
3239
                                 self.op.instance_name)
3240
    self.instance = instance
3241

  
3242
    remote_node = self.cfg.ExpandNodeName(self.op.remote_node)
3243
    if remote_node is None:
3244
      raise errors.OpPrereqError("Node '%s' not known" % self.op.remote_node)
3245
    self.remote_node = remote_node
3246

  
3247
    if remote_node == instance.primary_node:
3248
      raise errors.OpPrereqError("The specified node is the primary node of"
3249
                                 " the instance.")
3250

  
3251
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3252
      raise errors.OpPrereqError("Instance's disk layout is not"
3253
                                 " remote_raid1.")
3254
    for disk in instance.disks:
3255
      if disk.iv_name == self.op.disk_name:
3256
        break
3257
    else:
3258
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
3259
                                 " instance." % self.op.disk_name)
3260
    if len(disk.children) > 1:
3261
      raise errors.OpPrereqError("The device already has two slave devices."
3262
                                 " This would create a 3-disk raid1 which we"
3263
                                 " don't allow.")
3264
    self.disk = disk
3265

  
3266
  def Exec(self, feedback_fn):
3267
    """Add the mirror component
3268

  
3269
    """
3270
    disk = self.disk
3271
    instance = self.instance
3272

  
3273
    remote_node = self.remote_node
3274
    lv_names = [".%s_%s" % (disk.iv_name, suf) for suf in ["data", "meta"]]
3275
    names = _GenerateUniqueNames(self.cfg, lv_names)
3276
    new_drbd = _GenerateMDDRBDBranch(self.cfg, instance.primary_node,
3277
                                     remote_node, disk.size, names)
3278

  
3279
    logger.Info("adding new mirror component on secondary")
3280
    #HARDCODE
3281
    if not _CreateBlockDevOnSecondary(self.cfg, remote_node, instance,
3282
                                      new_drbd, False,
3283
                                      _GetInstanceInfoText(instance)):
3284
      raise errors.OpExecError("Failed to create new component on secondary"
3285
                               " node %s" % remote_node)
3286

  
3287
    logger.Info("adding new mirror component on primary")
3288
    #HARDCODE
3289
    if not _CreateBlockDevOnPrimary(self.cfg, instance.primary_node,
3290
                                    instance, new_drbd,
3291
                                    _GetInstanceInfoText(instance)):
3292
      # remove secondary dev
3293
      self.cfg.SetDiskID(new_drbd, remote_node)
3294
      rpc.call_blockdev_remove(remote_node, new_drbd)
3295
      raise errors.OpExecError("Failed to create volume on primary")
3296

  
3297
    # the device exists now
3298
    # call the primary node to add the mirror to md
3299
    logger.Info("adding new mirror component to md")
3300
    if not rpc.call_blockdev_addchildren(instance.primary_node,
3301
                                         disk, [new_drbd]):
3302
      logger.Error("Can't add mirror compoment to md!")
3303
      self.cfg.SetDiskID(new_drbd, remote_node)
3304
      if not rpc.call_blockdev_remove(remote_node, new_drbd):
3305
        logger.Error("Can't rollback on secondary")
3306
      self.cfg.SetDiskID(new_drbd, instance.primary_node)
3307
      if not rpc.call_blockdev_remove(instance.primary_node, new_drbd):
3308
        logger.Error("Can't rollback on primary")
3309
      raise errors.OpExecError("Can't add mirror component to md array")
3310

  
3311
    disk.children.append(new_drbd)
3312

  
3313
    self.cfg.AddInstance(instance)
3314

  
3315
    _WaitForSync(self.cfg, instance, self.proc)
3316

  
3317
    return 0
3318

  
3319

  
3320
class LURemoveMDDRBDComponent(LogicalUnit):
3321
  """Remove a component from a remote_raid1 disk.
3322

  
3323
  """
3324
  HPATH = "mirror-remove"
3325
  HTYPE = constants.HTYPE_INSTANCE
3326
  _OP_REQP = ["instance_name", "disk_name", "disk_id"]
3327

  
3328
  def BuildHooksEnv(self):
3329
    """Build hooks env.
3330

  
3331
    This runs on the master, the primary and all the secondaries.
3332

  
3333
    """
3334
    env = {
3335
      "DISK_NAME": self.op.disk_name,
3336
      "DISK_ID": self.op.disk_id,
3337
      "OLD_SECONDARY": self.old_secondary,
3338
      }
3339
    env.update(_BuildInstanceHookEnvByObject(self.instance))
3340
    nl = [self.sstore.GetMasterNode(),
3341
          self.instance.primary_node] + list(self.instance.secondary_nodes)
3342
    return env, nl, nl
3343

  
3344
  def CheckPrereq(self):
3345
    """Check prerequisites.
3346

  
3347
    This checks that the instance is in the cluster.
3348

  
3349
    """
3350
    instance = self.cfg.GetInstanceInfo(
3351
      self.cfg.ExpandInstanceName(self.op.instance_name))
3352
    if instance is None:
3353
      raise errors.OpPrereqError("Instance '%s' not known" %
3354
                                 self.op.instance_name)
3355
    self.instance = instance
3356

  
3357
    if instance.disk_template != constants.DT_REMOTE_RAID1:
3358
      raise errors.OpPrereqError("Instance's disk layout is not"
3359
                                 " remote_raid1.")
3360
    for disk in instance.disks:
3361
      if disk.iv_name == self.op.disk_name:
3362
        break
3363
    else:
3364
      raise errors.OpPrereqError("Can't find this device ('%s') in the"
3365
                                 " instance." % self.op.disk_name)
3366
    for child in disk.children:
3367
      if (child.dev_type == constants.LD_DRBD7 and
3368
          child.logical_id[2] == self.op.disk_id):
3369
        break
3370
    else:
3371
      raise errors.OpPrereqError("Can't find the device with this port.")
3372

  
3373
    if len(disk.children) < 2:
3374
      raise errors.OpPrereqError("Cannot remove the last component from"
3375
                                 " a mirror.")
3376
    self.disk = disk
3377
    self.child = child
3378
    if self.child.logical_id[0] == instance.primary_node:
3379
      oid = 1
3380
    else:
3381
      oid = 0
3382
    self.old_secondary = self.child.logical_id[oid]
3383

  
3384
  def Exec(self, feedback_fn):
3385
    """Remove the mirror component
3386

  
3387
    """
3388
    instance = self.instance
3389
    disk = self.disk
3390
    child = self.child
3391
    logger.Info("remove mirror component")
3392
    self.cfg.SetDiskID(disk, instance.primary_node)
3393
    if not rpc.call_blockdev_removechildren(instance.primary_node,
3394
                                            disk, [child]):
3395
      raise errors.OpExecError("Can't remove child from mirror.")
3396

  
3397
    for node in child.logical_id[:2]:
3398
      self.cfg.SetDiskID(child, node)
3399
      if not rpc.call_blockdev_remove(node, child):
3400
        logger.Error("Warning: failed to remove device from node %s,"
3401
                     " continuing operation." % node)
3402

  
3403
    disk.children.remove(child)
3404
    self.cfg.AddInstance(instance)
3405

  
3406

  
3407 3206
class LUReplaceDisks(LogicalUnit):
3408 3207
  """Replace the disks of an instance.
3409 3208

  
b/lib/mcpu.py
68 68
    opcodes.OpStartupInstance: cmdlib.LUStartupInstance,
69 69
    opcodes.OpRebootInstance: cmdlib.LURebootInstance,
70 70
    opcodes.OpDeactivateInstanceDisks: cmdlib.LUDeactivateInstanceDisks,
71
    opcodes.OpAddMDDRBDComponent: cmdlib.LUAddMDDRBDComponent,
72
    opcodes.OpRemoveMDDRBDComponent: cmdlib.LURemoveMDDRBDComponent,
73 71
    opcodes.OpReplaceDisks: cmdlib.LUReplaceDisks,
74 72
    opcodes.OpFailoverInstance: cmdlib.LUFailoverInstance,
75 73
    opcodes.OpConnectConsole: cmdlib.LUConnectConsole,
b/lib/opcodes.py
301 301
               "ignore_secondaries" ]
302 302

  
303 303

  
304
class OpAddMDDRBDComponent(OpCode):
305
  """Add a MD-DRBD component."""
306
  OP_ID = "OP_INSTANCE_ADD_MDDRBD"
307
  __slots__ = ["instance_name", "remote_node", "disk_name"]
308

  
309

  
310
class OpRemoveMDDRBDComponent(OpCode):
311
  """Remove a MD-DRBD component."""
312
  OP_ID = "OP_INSTANCE_REMOVE_MDDRBD"
313
  __slots__ = ["instance_name", "disk_name", "disk_id"]
314

  
315

  
316 304
class OpReplaceDisks(OpCode):
317 305
  """Replace the disks of an instance."""
318 306
  OP_ID = "OP_INSTANCE_REPLACE_DISKS"
b/man/gnt-instance.sgml
896 896
      </refsect3>
897 897

  
898 898
      <refsect3>
899
        <title>ADD-MIRROR</title>
900
        <cmdsynopsis>
901
          <command>add-mirror</command>
902
          <arg choice="req">-b <replaceable>sdX</replaceable></arg>
903
          <arg choice="req">-n <replaceable>node</replaceable></arg>
904
          <arg choice="req"><replaceable>instance</replaceable></arg>
905
        </cmdsynopsis>
906
        <para>
907
          Adds a new mirror to the disk layout of the instance, if the
908
          instance has a remote raid disk layout.
909

  
910
          The new mirror member will be between the instance's primary
911
          node and the node given with the <option>-n</option> option.
912
        </para>
913
      </refsect3>
914

  
915
      <refsect3>
916
        <title>REMOVE-MIRROR</title>
917

  
918
        <cmdsynopsis>
919
          <command>removemirror</command>
920
          <arg choice="req">-b <replaceable>sdX</replaceable></arg>
921
          <arg choice="req">-p <replaceable>id</replaceable></arg>
922
          <arg choice="req"><replaceable>instance</replaceable></arg>
923
        </cmdsynopsis>
924
        <para>
925
          Removes a mirror componenent from the disk layout of the
926
          instance, if the instance has a remote raid disk layout.
927
        </para>
928

  
929
        <para>
930
          You need to specifiy on which disk to act on using the
931
          <option>-b</option> option (either <filename>sda</filename>
932
          or <filename>sdb</filename>) and the mirror component, which
933
          is identified by the <option>-p</option> option. You can
934
          find the list of valid identifiers with the
935
          <command>info</command> command.
936
        </para>
937

  
938
      <refsect3>
939 899
        <title>ACTIVATE-DISKS</title>
940 900

  
941 901
        <cmdsynopsis>
b/scripts/gnt-instance
435 435
  return 0
436 436

  
437 437

  
438
def AddMDDRBDComponent(opts, args):
439
  """Add a new component to a remote_raid1 disk.
440

  
441
  Args:
442
    opts - class with options as members
443
    args - list with a single element, the instance name
444

  
445
  """
446
  op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
447
                                    disk_name=opts.disk,
448
                                    remote_node=opts.node)
449
  SubmitOpCode(op)
450
  return 0
451

  
452

  
453
def RemoveMDDRBDComponent(opts, args):
454
  """Remove a component from a remote_raid1 disk.
455

  
456
  Args:
457
    opts - class with options as members
458
    args - list with a single element, the instance name
459

  
460
  """
461
  op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
462
                                       disk_name=opts.disk,
463
                                       disk_id=opts.port)
464
  SubmitOpCode(op)
465
  return 0
466

  
467

  
468 438
def ReplaceDisks(opts, args):
469 439
  """Replace the disks of an instance
470 440

  
......
792 762
  'add': (AddInstance, ARGS_ONE, add_opts,
793 763
          "[opts...] <name>",
794 764
          "Creates and adds a new instance to the cluster"),
795
  'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
796
                [DEBUG_OPT, node_opt,
797
                 make_option("-b", "--disk", dest="disk", metavar="sdX",
798
                             help=("The name of the instance disk for which to"
799
                                   " add the mirror"))],
800
                "-n node -b disk <instance>",
801
                "Creates a new mirror for the instance"),
802 765
  'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
803 766
              "<instance>",
804 767
              "Opens a console on the specified instance"),
......
833 796
                                " process (shutdown, disk removal, etc.)")),
834 797
              ],
835 798
             "[-f] <instance>", "Shuts down the instance and removes it"),
836
  'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
837
                   [DEBUG_OPT, node_opt,
838
                    make_option("-b", "--disk", dest="disk", metavar="sdX",
839
                                help=("The name of the instance disk"
840
                                      " for which to add the mirror")),
841
                    make_option("-p", "--port", dest="port", metavar="PORT",
842
                                help=("The port of the drbd device"
843
                                      " which to remove from the mirror"),
844
                                type="int"),
845
                    ],
846
                   "-b disk -p port <instance>",
847
                   "Removes a mirror from the instance"),
848 799
  'rename': (RenameInstance, ARGS_FIXED(2),
849 800
             [DEBUG_OPT,
850 801
              make_option("--no-ip-check", dest="ignore_ip",

Also available in: Unified diff