Revision 08db7c5c lib/cmdlib.py

b/lib/cmdlib.py
3141 3141

  
3142 3142
def _GenerateDiskTemplate(lu, template_name,
3143 3143
                          instance_name, primary_node,
3144
                          secondary_nodes, disk_sz, swap_sz,
3144
                          secondary_nodes, disk_info,
3145 3145
                          file_storage_dir, file_driver):
3146 3146
  """Generate the entire disk layout for a given template type.
3147 3147

  
......
3149 3149
  #TODO: compute space requirements
3150 3150

  
3151 3151
  vgname = lu.cfg.GetVGName()
3152
  disk_count = len(disk_info)
3153
  disks = []
3152 3154
  if template_name == constants.DT_DISKLESS:
3153
    disks = []
3155
    pass
3154 3156
  elif template_name == constants.DT_PLAIN:
3155 3157
    if len(secondary_nodes) != 0:
3156 3158
      raise errors.ProgrammerError("Wrong template configuration")
3157 3159

  
3158
    names = _GenerateUniqueNames(lu, [".sda", ".sdb"])
3159
    sda_dev = objects.Disk(dev_type=constants.LD_LV, size=disk_sz,
3160
                           logical_id=(vgname, names[0]),
3161
                           iv_name = "sda")
3162
    sdb_dev = objects.Disk(dev_type=constants.LD_LV, size=swap_sz,
3163
                           logical_id=(vgname, names[1]),
3164
                           iv_name = "sdb")
3165
    disks = [sda_dev, sdb_dev]
3160
    names = _GenerateUniqueNames(lu, [".disk%d" % i
3161
                                      for i in range(disk_count)])
3162
    for idx, disk in enumerate(disk_info):
3163
      disk_dev = objects.Disk(dev_type=constants.LD_LV, size=disk["size"],
3164
                              logical_id=(vgname, names[idx]),
3165
                              iv_name = "disk/%d" % idx)
3166
      disks.append(disk_dev)
3166 3167
  elif template_name == constants.DT_DRBD8:
3167 3168
    if len(secondary_nodes) != 1:
3168 3169
      raise errors.ProgrammerError("Wrong template configuration")
3169 3170
    remote_node = secondary_nodes[0]
3170
    (minor_pa, minor_pb,
3171
     minor_sa, minor_sb) = lu.cfg.AllocateDRBDMinor(
3172
      [primary_node, primary_node, remote_node, remote_node], instance_name)
3173

  
3174
    names = _GenerateUniqueNames(lu, [".sda_data", ".sda_meta",
3175
                                      ".sdb_data", ".sdb_meta"])
3176
    drbd_sda_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
3177
                                        disk_sz, names[0:2], "sda",
3178
                                        minor_pa, minor_sa)
3179
    drbd_sdb_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
3180
                                        swap_sz, names[2:4], "sdb",
3181
                                        minor_pb, minor_sb)
3182
    disks = [drbd_sda_dev, drbd_sdb_dev]
3171
    minors = lu.cfg.AllocateDRBDMinor(
3172
      [primary_node, remote_node] * len(disk_info), instance_name)
3173

  
3174
    names = _GenerateUniqueNames(lu,
3175
                                 [".disk%d_%s" % (i, s)
3176
                                  for i in range(disk_count)
3177
                                  for s in ("data", "meta")
3178
                                  ])
3179
    for idx, disk in enumerate(disk_info):
3180
      disk_dev = _GenerateDRBD8Branch(lu, primary_node, remote_node,
3181
                                      disk["size"], names[idx*2:idx*2+2],
3182
                                      "disk/%d" % idx,
3183
                                      minors[idx*2], minors[idx*2+1])
3184
      disks.append(disk_dev)
3183 3185
  elif template_name == constants.DT_FILE:
3184 3186
    if len(secondary_nodes) != 0:
3185 3187
      raise errors.ProgrammerError("Wrong template configuration")
3186 3188

  
3187
    file_sda_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk_sz,
3188
                                iv_name="sda", logical_id=(file_driver,
3189
                                "%s/sda" % file_storage_dir))
3190
    file_sdb_dev = objects.Disk(dev_type=constants.LD_FILE, size=swap_sz,
3191
                                iv_name="sdb", logical_id=(file_driver,
3192
                                "%s/sdb" % file_storage_dir))
3193
    disks = [file_sda_dev, file_sdb_dev]
3189
    for idx, disk in enumerate(disk_info):
3190

  
3191
      disk_dev = objects.Disk(dev_type=constants.LD_FILE, size=disk["size"],
3192
                              iv_name="disk/%d" % idx,
3193
                              logical_id=(file_driver,
3194
                                          "%s/disk%d" % (file_storage_dir,
3195
                                                         idx)))
3196
      disks.append(disk_dev)
3194 3197
  else:
3195 3198
    raise errors.ProgrammerError("Invalid disk template '%s'" % template_name)
3196 3199
  return disks
......
3285 3288
  return result
3286 3289

  
3287 3290

  
3288
def _ComputeDiskSize(disk_template, disk_size, swap_size):
3291
def _ComputeDiskSize(disk_template, disks):
3289 3292
  """Compute disk size requirements in the volume group
3290 3293

  
3291 3294
  This is currently hard-coded for the two-drive layout.
......
3294 3297
  # Required free disk space as a function of disk and swap space
3295 3298
  req_size_dict = {
3296 3299
    constants.DT_DISKLESS: None,
3297
    constants.DT_PLAIN: disk_size + swap_size,
3298
    # 256 MB are added for drbd metadata, 128MB for each drbd device
3299
    constants.DT_DRBD8: disk_size + swap_size + 256,
3300
    constants.DT_PLAIN: sum(d["size"] for d in disks),
3301
    # 128 MB are added for drbd metadata for each disk
3302
    constants.DT_DRBD8: sum(d["size"] + 128 for d in disks),
3300 3303
    constants.DT_FILE: None,
3301 3304
  }
3302 3305

  
......
3343 3346
  """
3344 3347
  HPATH = "instance-add"
3345 3348
  HTYPE = constants.HTYPE_INSTANCE
3346
  _OP_REQP = ["instance_name", "disk_size",
3347
              "disk_template", "swap_size", "mode", "start",
3348
              "wait_for_sync", "ip_check", "mac",
3349
  _OP_REQP = ["instance_name", "disks", "disk_template",
3350
              "mode", "start",
3351
              "wait_for_sync", "ip_check", "nics",
3349 3352
              "hvparams", "beparams"]
3350 3353
  REQ_BGL = False
3351 3354

  
......
3418 3421

  
3419 3422
    self.add_locks[locking.LEVEL_INSTANCE] = instance_name
3420 3423

  
3421
    # ip validity checks
3422
    ip = getattr(self.op, "ip", None)
3423
    if ip is None or ip.lower() == "none":
3424
      inst_ip = None
3425
    elif ip.lower() == constants.VALUE_AUTO:
3426
      inst_ip = hostname1.ip
3427
    else:
3428
      if not utils.IsValidIP(ip):
3429
        raise errors.OpPrereqError("given IP address '%s' doesn't look"
3430
                                   " like a valid IP" % ip)
3431
      inst_ip = ip
3432
    self.inst_ip = self.op.ip = inst_ip
3424
    # NIC buildup
3425
    self.nics = []
3426
    for nic in self.op.nics:
3427
      # ip validity checks
3428
      ip = nic.get("ip", None)
3429
      if ip is None or ip.lower() == "none":
3430
        nic_ip = None
3431
      elif ip.lower() == constants.VALUE_AUTO:
3432
        nic_ip = hostname1.ip
3433
      else:
3434
        if not utils.IsValidIP(ip):
3435
          raise errors.OpPrereqError("Given IP address '%s' doesn't look"
3436
                                     " like a valid IP" % ip)
3437
        nic_ip = ip
3438

  
3439
      # MAC address verification
3440
      mac = nic.get("mac", constants.VALUE_AUTO)
3441
      if mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
3442
        if not utils.IsValidMac(mac.lower()):
3443
          raise errors.OpPrereqError("Invalid MAC address specified: %s" %
3444
                                     mac)
3445
      # bridge verification
3446
      bridge = nic.get("bridge", self.cfg.GetDefBridge())
3447
      self.nics.append(objects.NIC(mac=mac, ip=nic_ip, bridge=bridge))
3448

  
3449
    # disk checks/pre-build
3450
    self.disks = []
3451
    for disk in self.op.disks:
3452
      mode = disk.get("mode", constants.DISK_RDWR)
3453
      if mode not in constants.DISK_ACCESS_SET:
3454
        raise errors.OpPrereqError("Invalid disk access mode '%s'" %
3455
                                   mode)
3456
      size = disk.get("size", None)
3457
      if size is None:
3458
        raise errors.OpPrereqError("Missing disk size")
3459
      try:
3460
        size = int(size)
3461
      except ValueError:
3462
        raise errors.OpPrereqError("Invalid disk size '%s'" % size)
3463
      self.disks.append({"size": size, "mode": mode})
3464

  
3433 3465
    # used in CheckPrereq for ip ping check
3434 3466
    self.check_ip = hostname1.ip
3435 3467

  
3436
    # MAC address verification
3437
    if self.op.mac not in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
3438
      if not utils.IsValidMac(self.op.mac.lower()):
3439
        raise errors.OpPrereqError("invalid MAC address specified: %s" %
3440
                                   self.op.mac)
3441

  
3442 3468
    # file storage checks
3443 3469
    if (self.op.file_driver and
3444 3470
        not self.op.file_driver in constants.FILE_DRIVER):
......
3487 3513
    """Run the allocator based on input opcode.
3488 3514

  
3489 3515
    """
3490
    disks = [{"size": self.op.disk_size, "mode": "w"},
3491
             {"size": self.op.swap_size, "mode": "w"}]
3492
    nics = [{"mac": self.op.mac, "ip": getattr(self.op, "ip", None),
3493
             "bridge": self.op.bridge}]
3516
    nics = [n.ToDict() for n in self.nics]
3494 3517
    ial = IAllocator(self,
3495 3518
                     mode=constants.IALLOCATOR_MODE_ALLOC,
3496 3519
                     name=self.op.instance_name,
......
3499 3522
                     os=self.op.os_type,
3500 3523
                     vcpus=self.be_full[constants.BE_VCPUS],
3501 3524
                     mem_size=self.be_full[constants.BE_MEMORY],
3502
                     disks=disks,
3525
                     disks=self.disks,
3503 3526
                     nics=nics,
3504 3527
                     )
3505 3528

  
......
3529 3552
    """
3530 3553
    env = {
3531 3554
      "INSTANCE_DISK_TEMPLATE": self.op.disk_template,
3532
      "INSTANCE_DISK_SIZE": self.op.disk_size,
3533
      "INSTANCE_SWAP_SIZE": self.op.swap_size,
3555
      "INSTANCE_DISK_SIZE": ",".join(str(d["size"]) for d in self.disks),
3534 3556
      "INSTANCE_ADD_MODE": self.op.mode,
3535 3557
      }
3536 3558
    if self.op.mode == constants.INSTANCE_IMPORT:
......
3545 3567
      os_type=self.op.os_type,
3546 3568
      memory=self.be_full[constants.BE_MEMORY],
3547 3569
      vcpus=self.be_full[constants.BE_VCPUS],
3548
      nics=[(self.inst_ip, self.op.bridge, self.op.mac)],
3570
      nics=[(n.ip, n.bridge, n.mac) for n in self.nics],
3549 3571
    ))
3550 3572

  
3551 3573
    nl = ([self.cfg.GetMasterNode(), self.op.pnode] +
......
3581 3603
                                   (ei_version, constants.EXPORT_VERSION))
3582 3604

  
3583 3605
      # Check that the new instance doesn't have less disks than the export
3584
      # TODO: substitute "2" with the actual number of disks requested
3585
      instance_disks = 2
3606
      instance_disks = len(self.disks)
3586 3607
      export_disks = export_info.getint(constants.INISECT_INS, 'disk_count')
3587 3608
      if instance_disks < export_disks:
3588 3609
        raise errors.OpPrereqError("Not enough disks to import."
......
3622 3643
        raise errors.OpPrereqError("IP %s of instance %s already in use" %
3623 3644
                                   (self.check_ip, self.op.instance_name))
3624 3645

  
3625
    # bridge verification
3626
    bridge = getattr(self.op, "bridge", None)
3627
    if bridge is None:
3628
      self.op.bridge = self.cfg.GetDefBridge()
3629
    else:
3630
      self.op.bridge = bridge
3631

  
3632 3646
    #### allocator run
3633 3647

  
3634 3648
    if self.op.iallocator is not None:
......
3655 3669
    nodenames = [pnode.name] + self.secondaries
3656 3670

  
3657 3671
    req_size = _ComputeDiskSize(self.op.disk_template,
3658
                                self.op.disk_size, self.op.swap_size)
3672
                                self.disks)
3659 3673

  
3660 3674
    # Check lv size requirements
3661 3675
    if req_size is not None:
......
3684 3698
                                 " primary node"  % self.op.os_type)
3685 3699

  
3686 3700
    # bridge check on primary node
3687
    if not self.rpc.call_bridges_exist(self.pnode.name, [self.op.bridge]):
3688
      raise errors.OpPrereqError("target bridge '%s' does not exist on"
3701
    bridges = [n.bridge for n in self.nics]
3702
    if not self.rpc.call_bridges_exist(self.pnode.name, bridges):
3703
      raise errors.OpPrereqError("one of the target bridges '%s' does not"
3704
                                 " exist on"
3689 3705
                                 " destination node '%s'" %
3690
                                 (self.op.bridge, pnode.name))
3706
                                 (",".join(bridges), pnode.name))
3691 3707

  
3692 3708
    # memory check on primary node
3693 3709
    if self.op.start:
......
3708 3724
    instance = self.op.instance_name
3709 3725
    pnode_name = self.pnode.name
3710 3726

  
3711
    if self.op.mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
3712
      mac_address = self.cfg.GenerateMAC()
3713
    else:
3714
      mac_address = self.op.mac
3715

  
3716
    nic = objects.NIC(bridge=self.op.bridge, mac=mac_address)
3717
    if self.inst_ip is not None:
3718
      nic.ip = self.inst_ip
3727
    for nic in self.nics:
3728
      if nic.mac in (constants.VALUE_AUTO, constants.VALUE_GENERATE):
3729
        nic.mac = self.cfg.GenerateMAC()
3719 3730

  
3720 3731
    ht_kind = self.op.hypervisor
3721 3732
    if ht_kind in constants.HTS_REQ_PORT:
......
3741 3752
    disks = _GenerateDiskTemplate(self,
3742 3753
                                  self.op.disk_template,
3743 3754
                                  instance, pnode_name,
3744
                                  self.secondaries, self.op.disk_size,
3745
                                  self.op.swap_size,
3755
                                  self.secondaries,
3756
                                  self.disks,
3746 3757
                                  file_storage_dir,
3747 3758
                                  self.op.file_driver)
3748 3759

  
3749 3760
    iobj = objects.Instance(name=instance, os=self.op.os_type,
3750 3761
                            primary_node=pnode_name,
3751
                            nics=[nic], disks=disks,
3762
                            nics=self.nics, disks=disks,
3752 3763
                            disk_template=self.op.disk_template,
3753 3764
                            status=self.instance_status,
3754 3765
                            network_port=network_port,

Also available in: Unified diff