Revision c3589cf8

b/lib/cmdlib.py
5804 5804
        not constants.ENABLE_FILE_STORAGE):
5805 5805
      raise errors.OpPrereqError("File storage disabled at configure time",
5806 5806
                                 errors.ECODE_INVAL)
5807
    # check disk information: either all adopt, or no adopt
5808
    has_adopt = has_no_adopt = False
5809
    for disk in self.op.disks:
5810
      if "adopt" in disk:
5811
        has_adopt = True
5812
      else:
5813
        has_no_adopt = True
5814
    if has_adopt and has_no_adopt:
5815
      raise errors.OpPrereqError("Either all disks have are adoped or none is",
5816
                                 errors.ECODE_INVAL)
5817
    if has_adopt:
5818
      if self.op.disk_template != constants.DT_PLAIN:
5819
        raise errors.OpPrereqError("Disk adoption is only supported for the"
5820
                                   " 'plain' disk template",
5821
                                   errors.ECODE_INVAL)
5822
      if self.op.iallocator is not None:
5823
        raise errors.OpPrereqError("Disk adoption not allowed with an"
5824
                                   " iallocator script", errors.ECODE_INVAL)
5825
      if self.op.mode == constants.INSTANCE_IMPORT:
5826
        raise errors.OpPrereqError("Disk adoption not allowed for"
5827
                                   " instance import", errors.ECODE_INVAL)
5828

  
5829
    self.adopt_disks = has_adopt
5807 5830

  
5808 5831
  def ExpandNames(self):
5809 5832
    """ExpandNames for CreateInstance.
......
5958 5981
      except (TypeError, ValueError):
5959 5982
        raise errors.OpPrereqError("Invalid disk size '%s'" % size,
5960 5983
                                   errors.ECODE_INVAL)
5961
      self.disks.append({"size": size, "mode": mode})
5984
      new_disk = {"size": size, "mode": mode}
5985
      if "adopt" in disk:
5986
        new_disk["adopt"] = disk["adopt"]
5987
      self.disks.append(new_disk)
5962 5988

  
5963 5989
    # file storage checks
5964 5990
    if (self.op.file_driver and
......
6227 6253
    req_size = _ComputeDiskSize(self.op.disk_template,
6228 6254
                                self.disks)
6229 6255

  
6230
    # Check lv size requirements
6231
    if req_size is not None:
6256
    # Check lv size requirements, if not adopting
6257
    if req_size is not None and not self.adopt_disks:
6232 6258
      nodeinfo = self.rpc.call_node_info(nodenames, self.cfg.GetVGName(),
6233 6259
                                         self.op.hypervisor)
6234 6260
      for node in nodenames:
......
6245 6271
                                     (node, vg_free, req_size),
6246 6272
                                     errors.ECODE_NORES)
6247 6273

  
6274
    if self.adopt_disks: # instead, we must check the adoption data
6275
      all_lvs = set([i["adopt"] for i in self.disks])
6276
      if len(all_lvs) != len(self.disks):
6277
        raise errors.OpPrereqError("Duplicate volume names given for adoption",
6278
                                   errors.ECODE_INVAL)
6279
      for lv_name in all_lvs:
6280
        try:
6281
          self.cfg.ReserveLV(lv_name, self.proc.GetECId())
6282
        except errors.ReservationError:
6283
          raise errors.OpPrereqError("LV named %s used by another instance" %
6284
                                     lv_name, errors.ECODE_NOTUNIQUE)
6285

  
6286
      node_lvs = self.rpc.call_lv_list([pnode.name],
6287
                                       self.cfg.GetVGName())[pnode.name]
6288
      node_lvs.Raise("Cannot get LV information from node %s" % pnode.name)
6289
      node_lvs = node_lvs.payload
6290
      delta = all_lvs.difference(node_lvs.keys())
6291
      if delta:
6292
        raise errors.OpPrereqError("Missing logical volume(s): %s" %
6293
                                   utils.CommaJoin(delta),
6294
                                   errors.ECODE_INVAL)
6295
      online_lvs = [lv for lv in all_lvs if node_lvs[lv][2]]
6296
      if online_lvs:
6297
        raise errors.OpPrereqError("Online logical volumes found, cannot"
6298
                                   " adopt: %s" % utils.CommaJoin(online_lvs),
6299
                                   errors.ECODE_STATE)
6300
      # update the size of disk based on what is found
6301
      for dsk in self.disks:
6302
        dsk["size"] = int(float(node_lvs[dsk["adopt"]][0]))
6303

  
6248 6304
    _CheckHVParams(self, nodenames, self.op.hypervisor, self.op.hvparams)
6249 6305

  
6250 6306
    # os verification
......
6313 6369
                            hypervisor=self.op.hypervisor,
6314 6370
                            )
6315 6371

  
6316
    feedback_fn("* creating instance disks...")
6317
    try:
6318
      _CreateDisks(self, iobj)
6319
    except errors.OpExecError:
6320
      self.LogWarning("Device creation failed, reverting...")
6372
    if self.adopt_disks:
6373
      # rename LVs to the newly-generated names; we need to construct
6374
      # 'fake' LV disks with the old data, plus the new unique_id
6375
      tmp_disks = [objects.Disk.FromDict(v.ToDict()) for v in disks]
6376
      rename_to = []
6377
      for t_dsk, a_dsk in zip (tmp_disks, self.disks):
6378
        rename_to.append(t_dsk.logical_id)
6379
        t_dsk.logical_id = (t_dsk.logical_id[0], a_dsk["adopt"])
6380
        self.cfg.SetDiskID(t_dsk, pnode_name)
6381
      result = self.rpc.call_blockdev_rename(pnode_name,
6382
                                             zip(tmp_disks, rename_to))
6383
      result.Raise("Failed to rename adoped LVs")
6384
    else:
6385
      feedback_fn("* creating instance disks...")
6321 6386
      try:
6322
        _RemoveDisks(self, iobj)
6323
      finally:
6324
        self.cfg.ReleaseDRBDMinors(instance)
6325
        raise
6387
        _CreateDisks(self, iobj)
6388
      except errors.OpExecError:
6389
        self.LogWarning("Device creation failed, reverting...")
6390
        try:
6391
          _RemoveDisks(self, iobj)
6392
        finally:
6393
          self.cfg.ReleaseDRBDMinors(instance)
6394
          raise
6326 6395

  
6327 6396
    feedback_fn("adding instance %s to cluster config" % instance)
6328 6397

  
......
6360 6429
      raise errors.OpExecError("There are some degraded disks for"
6361 6430
                               " this instance")
6362 6431

  
6363
    feedback_fn("creating os for instance %s on node %s" %
6364
                (instance, pnode_name))
6365

  
6366
    if iobj.disk_template != constants.DT_DISKLESS:
6432
    if iobj.disk_template != constants.DT_DISKLESS and not self.adopt_disks:
6367 6433
      if self.op.mode == constants.INSTANCE_CREATE:
6368 6434
        feedback_fn("* running the instance OS create scripts...")
6369 6435
        # FIXME: pass debug option from opcode to backend

Also available in: Unified diff