Revision 0fe22ad2

b/lib/errors.py
102 102
  """
103 103

  
104 104

  
105
class HotplugError(HypervisorError):
106
  """Hotplug-related exception.
107

  
108
  This is raised in case a hotplug action fails or is not supported.
109
  It is currently used only by KVM hypervisor.
110

  
111
  """
112

  
113

  
105 114
class ProgrammerError(GenericError):
106 115
  """Programming-related error.
107 116

  
b/lib/hypervisor/hv_kvm.py
79 79
  constants.HV_KVM_SPICE_USE_TLS,
80 80
  ])
81 81

  
82
# below constants show the format of runtime file
83
# the nics are in second possition, while the disks in 4th (last)
84
# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
85
_KVM_NICS_RUNTIME_INDEX = 1
86
_KVM_DISKS_RUNTIME_INDEX = 3
87
_DEVICE_RUNTIME_INDEX = {
88
  constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX,
89
  constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX
90
  }
91
_FIND_RUNTIME_ENTRY = {
92
  constants.HOTPLUG_TARGET_NIC:
93
    lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid],
94
  constants.HOTPLUG_TARGET_DISK:
95
    lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks
96
                             if d.uuid == disk.uuid]
97
  }
98
_RUNTIME_DEVICE = {
99
  constants.HOTPLUG_TARGET_NIC: lambda d: d,
100
  constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d
101
  }
102
_RUNTIME_ENTRY = {
103
  constants.HOTPLUG_TARGET_NIC: lambda d, e: d,
104
  constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e, None)
105
  }
106

  
107

  
108
def _GetExistingDeviceInfo(dev_type, device, runtime):
109
  """Helper function to get an existing device inside the runtime file
110

  
111
  Used when an instance is running. Load kvm runtime file and search
112
  for a device based on its type and uuid.
113

  
114
  @type dev_type: sting
115
  @param dev_type: device type of param dev
116
  @type device: L{objects.Disk} or L{objects.NIC}
117
  @param device: the device object for which we generate a kvm name
118
  @type runtime: tuple (cmd, nics, hvparams, disks)
119
  @param runtime: the runtime data to search for the device
120
  @raise errors.HotplugError: in case the requested device does not
121
    exist (e.g. device has been added without --hotplug option) or
122
    device info has not pci slot (e.g. old devices in the cluster)
123

  
124
  """
125
  index = _DEVICE_RUNTIME_INDEX[dev_type]
126
  found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index])
127
  if not found:
128
    raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" %
129
                              (dev_type, device.uuid))
130

  
131
  return found[0]
132

  
133

  
134
def _AnalyzeSerializedRuntime(serialized_runtime):
135
  """Return runtime entries for a serialized runtime file
136

  
137
  @type serialized_runtime: string
138
  @param serialized_runtime: raw text data read from actual runtime file
139
  @return: (cmd, nics, hvparams, bdevs)
140
  @rtype: list
141

  
142
  """
143
  loaded_runtime = serializer.Load(serialized_runtime)
144
  if len(loaded_runtime) == 3:
145
    serialized_blockdevs = []
146
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
147
  else:
148
    kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
149

  
150
  kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
151
  block_devices = [(objects.Disk.FromDict(sdisk), link, uri)
152
                   for sdisk, link, uri in serialized_blockdevs]
153

  
154
  return (kvm_cmd, kvm_nics, hvparams, block_devices)
155

  
82 156

  
83 157
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
84 158
  """Retrieves supported TUN features from file descriptor.
......
1451 1525
    if hvp[constants.HV_KVM_EXTRA]:
1452 1526
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1453 1527

  
1454
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1455
                                                     block_devices,
1456
                                                     kvmhelp)
1457
    kvm_cmd.extend(bdev_opts)
1458
    # Save the current instance nics, but defer their expansion as parameters,
1459
    # as we'll need to generate executable temp files for them.
1460
    kvm_nics = instance.nics
1528
    kvm_disks = []
1529
    for disk, dev_path in block_devices:
1530
      kvm_disks.append((disk, dev_path))
1531

  
1532
    kvm_nics = []
1533
    for nic in instance.nics:
1534
      kvm_nics.append(nic)
1535

  
1461 1536
    hvparams = hvp
1462 1537

  
1463
    return (kvm_cmd, kvm_nics, hvparams)
1538
    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1464 1539

  
1465 1540
  def _WriteKVMRuntime(self, instance_name, data):
1466 1541
    """Write an instance's KVM runtime
......
1486 1561
    """Save an instance's KVM runtime
1487 1562

  
1488 1563
    """
1489
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
1564
    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
1565

  
1490 1566
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
1491
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1567
    serialized_blockdevs = [(blk.ToDict(), link, uri)
1568
                            for blk, link, uri in block_devices]
1569
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
1570
                                      serialized_blockdevs))
1571

  
1492 1572
    self._WriteKVMRuntime(instance.name, serialized_form)
1493 1573

  
1494 1574
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
......
1497 1577
    """
1498 1578
    if not serialized_runtime:
1499 1579
      serialized_runtime = self._ReadKVMRuntime(instance.name)
1500
    loaded_runtime = serializer.Load(serialized_runtime)
1501
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
1502
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1503
    return (kvm_cmd, kvm_nics, hvparams)
1580

  
1581
    return _AnalyzeSerializedRuntime(serialized_runtime)
1504 1582

  
1505 1583
  def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1506 1584
    """Run the KVM cmd and check for errors
......
1525 1603
    if not self._InstancePidAlive(name)[2]:
1526 1604
      raise errors.HypervisorError("Failed to start instance %s" % name)
1527 1605

  
1606
  # 52/50 local variables
1607
  # pylint: disable=R0914
1528 1608
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1529 1609
    """Execute a KVM cmd, after completing it with some last minute data.
1530 1610

  
......
1548 1628

  
1549 1629
    temp_files = []
1550 1630

  
1551
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1631
    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
1552 1632
    # the first element of kvm_cmd is always the path to the kvm binary
1553 1633
    kvm_path = kvm_cmd[0]
1554 1634
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
......
1652 1732
        continue
1653 1733
      self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1654 1734

  
1735
    bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
1736
                                                     block_devices,
1737
                                                     kvmhelp)
1738
    kvm_cmd.extend(bdev_opts)
1655 1739
    # CPU affinity requires kvm to start paused, so we set this flag if the
1656 1740
    # instance is not already paused and if we are not going to accept a
1657 1741
    # migrating instance. In the latter case, pausing is not needed.

Also available in: Unified diff