# below constants show the format of runtime file
# the nics are in second possition, while the disks in 4th (last)
-# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
+# moreover disk entries are stored as a list of in tuples
+# (L{objects.Disk}, link_name)
_KVM_NICS_RUNTIME_INDEX = 1
_KVM_DISKS_RUNTIME_INDEX = 3
_DEVICE_RUNTIME_INDEX = {
"""
loaded_runtime = serializer.Load(serialized_runtime)
if len(loaded_runtime) == 3:
- serialized_blockdevs = []
+ serialized_disks = []
kvm_cmd, serialized_nics, hvparams = loaded_runtime
else:
- kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
+ kvm_cmd, serialized_nics, hvparams, serialized_disks = loaded_runtime
kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
- block_devices = [(objects.Disk.FromDict(sdisk), link)
- for sdisk, link in serialized_blockdevs]
+ kvm_disks = [(objects.Disk.FromDict(sdisk), link)
+ for sdisk, link in serialized_disks]
- return (kvm_cmd, kvm_nics, hvparams, block_devices)
+ return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
@type tap: str
"""
- if instance.tags:
- tags = " ".join(instance.tags)
- else:
- tags = ""
-
env = {
"PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
"INSTANCE": instance.name,
"MODE": nic.nicparams[constants.NIC_MODE],
"INTERFACE": tap,
"INTERFACE_INDEX": str(seq),
- "TAGS": tags,
+ "TAGS": " ".join(instance.GetTags()),
}
if nic.ip:
data.append(info)
return data
- def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
+ def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
kvmhelp, devlist):
"""Generate KVM options regarding instance's block devices.
@type instance: L{objects.Instance}
@param instance: the instance object
- @type block_devices: list of tuples
- @param block_devices: list of tuples [(disk, link_name, uri)..]
+ @type kvm_disks: list of tuples
+ @param kvm_disks: list of tuples [(disk, link_name)..]
@type kvmhelp: string
@param kvmhelp: output of kvm --help
@type devlist: string
boot_disk = False
else:
boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
- kvm_path = hvp[constants.HV_KVM_PATH]
# whether this is an older KVM version that uses the boot=on flag
# on devices
cache_val = ",cache=%s" % disk_cache
else:
cache_val = ""
- for cfdev, dev_path in block_devices:
+ for cfdev, link_name in kvm_disks:
if cfdev.mode != constants.DISK_RDWR:
raise errors.HypervisorError("Instance has read-only disks which"
" are not supported by KVM")
(dev_path, if_val, boot_val, cache_val)
if device_driver:
- # block_devices are the 4th entry of runtime file that did not exist in
+ # kvm_disks are the 4th entry of runtime file that did not exist in
# the past. That means that cfdev should always have pci slot and
# _GenerateDeviceKVMId() will not raise a exception.
kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
"""Save an instance's KVM runtime
"""
- kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
+ kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
serialized_nics = [nic.ToDict() for nic in kvm_nics]
- serialized_blockdevs = [(blk.ToDict(), link)
- for blk, link in block_devices]
+ serialized_disks = [(blk.ToDict(), link)
+ for blk, link in kvm_disks]
serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
- serialized_blockdevs))
+ serialized_disks))
self._WriteKVMRuntime(instance.name, serialized_form)
if not self._InstancePidAlive(name)[2]:
raise errors.HypervisorError("Failed to start instance %s" % name)
- # 52/50 local variables
+ # too many local variables
# pylint: disable=R0914
def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
"""Execute a KVM cmd, after completing it with some last minute data.
temp_files = []
- kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
+ kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
# the first element of kvm_cmd is always the path to the kvm binary
kvm_path = kvm_cmd[0]
up_hvp = objects.FillDict(conf_hvp, up_hvp)
self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
- block_devices,
+ kvm_disks,
kvmhelp,
devlist)
kvm_cmd.extend(bdev_opts)
dev.pci = int(free)
- def HotplugSupported(self, instance, action, dev_type):
- """Check if hotplug is supported.
+ def VerifyHotplugSupport(self, instance, action, dev_type):
+ """Verifies that hotplug is supported.
Hotplug is *not* supported in case of:
- - qemu versions < 1.0
- security models and chroot (disk hotplug)
- fdsend module is missing (nic hot-add)
- @raise errors.HypervisorError: in previous cases
+ @raise errors.HypervisorError: in one of the previous cases
"""
- output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
- # TODO: search for netdev_add, drive_add, device_add.....
- match = self._INFO_VERSION_RE.search(output.stdout)
- if not match:
- raise errors.HotplugError("Try hotplug only in running instances.")
- v_major, v_min, _, _ = match.groups()
- if (int(v_major), int(v_min)) < (1, 0):
- raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
-
if dev_type == constants.HOTPLUG_TARGET_DISK:
hvp = instance.hvparams
security_model = hvp[constants.HV_SECURITY_MODEL]
action == constants.HOTPLUG_ACTION_ADD and not fdsend):
raise errors.HotplugError("Cannot hot-add NIC."
" fdsend python module is missing.")
- return True
+
+ def HotplugSupported(self, instance):
+ """Checks if hotplug is generally supported.
+
+ Hotplug is *not* supported in case of:
+ - qemu versions < 1.0
+ - for stopped instances
+
+ @raise errors.HypervisorError: in one of the previous cases
+
+ """
+ try:
+ output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
+ except errors.HypervisorError:
+ raise errors.HotplugError("Instance is probably down")
+
+ # TODO: search for netdev_add, drive_add, device_add.....
+ match = self._INFO_VERSION_RE.search(output.stdout)
+ if not match:
+ raise errors.HotplugError("Cannot parse qemu version via monitor")
+
+ v_major, v_min, _, _ = match.groups()
+ if (int(v_major), int(v_min)) < (1, 0):
+ raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
def _CallHotplugCommand(self, name, cmd):
output = self._CallMonitorCommand(name, cmd)
kvm_device = _RUNTIME_DEVICE[dev_type](entry)
kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
if dev_type == constants.HOTPLUG_TARGET_DISK:
- command = "device_del %s" % kvm_devid
+ command = "device_del %s\n" % kvm_devid
+ command += "drive_del %s" % kvm_devid
elif dev_type == constants.HOTPLUG_TARGET_NIC:
command = "device_del %s\n" % kvm_devid
command += "netdev_del %s" % kvm_devid