LGTM, thanks On Thu, Oct 8, 2015 at 5:40 AM, Dimitris Aragiorgis < [email protected]> wrote:
> Replace pci slot with hvinfo in Disk and NIC config Objects. This > will contain all the necessary info to construct a -device option. > Specifically, for PCI devices it will have driver, id, bus, and addr > fields. SCSI devices will have driver, id, bus, channel, scsi-id, > and lun fields. > > Change the way we generate the device ID so that it gets derived > only from the type and the UUID of the device (e.g. > disk-932df160-7a22-4067). We ensure seamless migration by upgrading > the existing runtime files in _UpgradeSerializedRuntime(). All > devices found with a 'pci' slot will get an 'hvinfo' dict with the > old id, bus 'pci.0', and addr based on the old value of 'pci'. > > Change the way we put devices into buses. Guessing the default > reserved PCI slots of an instance has proven to be error-prone, > since they may change from version to version, and also because the > PCI bus state may be modified with a specific option passed by the > user with the kvm_extra hvpamam. Therefore, we decide to start > adding PCI devices from slot 12 onwards. The SCSI bus does not need > to have default reservations. > > Let QEMU decide the PCI slot of spice, balloon and SCSI controller > devices. Finally, QEMU adds by default an LSI controller in case a > SCSI disk is attached to the instance. Here, we set it explicitly, > and name the created bus 'scsi.0' (as QEMU does by default). > > Until now, only SCSI emulated disks were supported. Allow > scsi-generic, scsi-block, scsi-hd, and scsi-cd for the disk_type > hvparams. The first two do SCSI pass-through and thus require a > physical SCSI device on the host. The third is the equivalent of > if=scsi, which means that the virtual disk of the instance will be an > emulated SCSI device. > > Signed-off-by: Dimitris Aragiorgis <[email protected]> > --- > lib/hypervisor/hv_kvm/__init__.py | 313 > ++++++++++++++++++++------ > lib/objects.py | 3 +- > src/Ganeti/Constants.hs | 25 +- > src/Ganeti/Types.hs | 4 +- > test/data/kvm_runtime.json | 21 +- > test/py/ganeti.hypervisor.hv_kvm_unittest.py | 53 ++++- > 6 files changed, 339 insertions(+), 80 deletions(-) > > diff --git a/lib/hypervisor/hv_kvm/__init__.py > b/lib/hypervisor/hv_kvm/__init__.py > index 340ddb1..67f2845 100644 > --- a/lib/hypervisor/hv_kvm/__init__.py > +++ b/lib/hypervisor/hv_kvm/__init__.py > @@ -109,6 +109,32 @@ _RUNTIME_ENTRY = { > constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1]) > } > > +_DEVICE_TYPE = { > + constants.HOTPLUG_TARGET_NIC: lambda hvp: hvp[constants.HV_NIC_TYPE], > + constants.HOTPLUG_TARGET_DISK: lambda hvp: hvp[constants.HV_DISK_TYPE], > + } > + > +_DEVICE_DRIVER = { > + constants.HOTPLUG_TARGET_NIC: > + lambda ht: "virtio-net-pci" if ht == constants.HT_NIC_PARAVIRTUAL > else ht, > + constants.HOTPLUG_TARGET_DISK: > + lambda ht: "virtio-blk-pci" if ht == constants.HT_DISK_PARAVIRTUAL > else ht, > + } > + > + > +# NICs and paravirtual disks > +# show up as devices on the PCI bus (one slot per device). > +# SCSI disks will be placed on the SCSI bus. > +_DEVICE_BUS = { > + constants.HOTPLUG_TARGET_NIC: > + lambda _: _PCI_BUS, > + constants.HOTPLUG_TARGET_DISK: > + lambda ht: _SCSI_BUS if ht in constants.HT_SCSI_DEVICE_TYPES else > _PCI_BUS > + } > + > +_PCI_BUS = "pci.0" > +_SCSI_BUS = "scsi.0" > + > _MIGRATION_CAPS_DELIM = ":" > > > @@ -155,23 +181,93 @@ def _GetDriveURI(disk, link, uri): > def _GenerateDeviceKVMId(dev_type, dev): > """Helper function to generate a unique device name used by KVM > > - QEMU monitor commands use names to identify devices. Here we use their > pci > - slot and a part of their UUID to name them. dev.pci might be None for > old > - devices in the cluster. > + QEMU monitor commands use names to identify devices. Since the UUID > + is too long for a device ID (36 chars vs. 30), we choose to use > + only the part until the third '-' with a disk/nic prefix. > + For example if a disk has UUID '932df160-7a22-4067-a566-7e0ca8386133' > + the resulting device ID would be 'disk-932df160-7a22-4067'. > > - @type dev_type: sting > - @param dev_type: device type of param dev > + @type dev_type: string > + @param dev_type: device type of param dev (HOTPLUG_TARGET_DISK|NIC) > @type dev: L{objects.Disk} or L{objects.NIC} > @param dev: the device object for which we generate a kvm name > - @raise errors.HotplugError: in case a device has no pci slot (old > devices) > > """ > + return "%s-%s" % (dev_type.lower(), dev.uuid.rsplit("-", 2)[0]) > + > + > +def _GenerateDeviceHVInfoStr(hvinfo): > + """Construct the -device option string for hvinfo dict > + > + PV disk: virtio-blk-pci,id=disk-1234,bus=pci.0,addr=0x9 > + PV NIC: virtio-net-pci,id=nic-1234,bus=pci.0,addr=0x9 > + SG disk: scsi-generic,id=disk-1234,bus=scsi.0,channel=0,scsi-id=1,lun=0 > + > + @type hvinfo: dict > + @param hvinfo: dictionary created by _GenerateDeviceHVInfo() > + > + @rtype: string > + @return: The constructed string to be passed along with a -device option > + > + """ > + > + # work on a copy > + d = dict(hvinfo) > + hvinfo_str = d.pop("driver") > + for k, v in d.items(): > + hvinfo_str += ",%s=%s" % (k, v) > + > + return hvinfo_str > + > + > +def _GenerateDeviceHVInfo(dev_type, kvm_devid, hv_dev_type, bus_slots): > + """Helper function to generate hvinfo of a device (disk, NIC) > + > + hvinfo will hold all necessary info for generating the -device QEMU > option. > + We have two main buses: a PCI bus and a SCSI bus (created by a SCSI > + controller on the PCI bus). > + > + In case of PCI devices we add them on a free PCI slot (addr) on the > first PCI > + bus (pci.0), and in case of SCSI devices we decide to put each disk on a > + different SCSI target (scsi-id) on the first SCSI bus (scsi.0). > + > + @type dev_type: string > + @param dev_type: either HOTPLUG_TARGET_DISK or HOTPLUG_TARGET_NIC > + @type kvm_devid: string > + @param kvm_devid: the id of the device > + @type hv_dev_type: string > + @param hv_dev_type: either disk_type or nic_type hvparam > + @type bus_slots: dict > + @param bus_slots: the current slots of the first PCI and SCSI buses > + > + @rtype: dict > + @return: dict including all necessary info (driver, id, bus and bus > location) > + for generating a -device QEMU option for either a disk or a NIC > + > + """ > + driver = _DEVICE_DRIVER[dev_type](hv_dev_type) > + bus = _DEVICE_BUS[dev_type](hv_dev_type) > + slots = bus_slots[bus] > + slot = utils.GetFreeSlot(slots, reserve=True) > + > + hvinfo = { > + "driver": driver, > + "id": kvm_devid, > + "bus": bus, > + } > > - if not dev.pci: > - raise errors.HotplugError("Hotplug is not supported for %s with UUID > %s" % > - (dev_type, dev.uuid)) > + if bus == _PCI_BUS: > + hvinfo.update({ > + "addr": hex(slot), > + }) > + elif bus == _SCSI_BUS: > + hvinfo.update({ > + "channel": 0, > + "scsi-id": slot, > + "lun": 0, > + }) > > - return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], > dev.pci) > + return hvinfo > > > def _GetExistingDeviceInfo(dev_type, device, runtime): > @@ -220,10 +316,38 @@ def _UpgradeSerializedRuntime(serialized_runtime): > else: > serialized_disks = [] > > + def update_hvinfo(dev, dev_type): > + """ Remove deprecated pci slot and substitute it with hvinfo """ > + if "hvinfo" not in dev: > + dev["hvinfo"] = {} > + uuid = dev["uuid"] > + # Ganeti used to save the PCI slot of paravirtual devices > + # (virtio-blk-pci, virtio-net-pci) in runtime files during > + # _GenerateKVMRuntime() and HotAddDevice(). > + # In this case we had a -device QEMU option in the command line > with id, > + # drive|netdev, bus, and addr params. All other devices did not > have an > + # id nor placed explicitly on a bus. > + # hot- prefix is removed in 2.16. Here we add it explicitly to > + # handle old instances in the cluster properly. > + if "pci" in dev: > + # This is practically the old _GenerateDeviceKVMId() > + dev["hvinfo"]["id"] = "hot%s-%s-%s-%s" % (dev_type.lower(), > + uuid.split("-")[0], > + "pci", > + dev["pci"]) > + dev["hvinfo"]["addr"] = hex(dev["pci"]) > + dev["hvinfo"]["bus"] = _PCI_BUS > + del dev["pci"] > + > for nic in serialized_nics: > # Add a dummy uuid slot if an pre-2.8 NIC is found > if "uuid" not in nic: > nic["uuid"] = utils.NewUUID() > + update_hvinfo(nic, constants.HOTPLUG_TARGET_NIC) > + > + for disk_entry in serialized_disks: > + # We have a (Disk, link, uri) tuple > + update_hvinfo(disk_entry[0], constants.HOTPLUG_TARGET_DISK) > > return kvm_cmd, serialized_nics, hvparams, serialized_disks > > @@ -405,8 +529,9 @@ class KVMHypervisor(hv_base.BaseHypervisor): > _NETDEV_RE = re.compile(r"^-netdev\s", re.M) > _DISPLAY_RE = re.compile(r"^-display\s", re.M) > _MACHINE_RE = re.compile(r"^-machine\s", re.M) > - _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M) > - _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M) > + _DEVICE_DRIVER_SUPPORTED = \ > + staticmethod(lambda drv, devlist: > + re.compile(r"^name \"%s\"" % drv, re.M).search(devlist)) > # match -drive.*boot=on|off on different lines, but in between accept > only > # dashes not preceeded by a new line (which would mean another option > # different than -drive is starting) > @@ -418,8 +543,20 @@ class KVMHypervisor(hv_base.BaseHypervisor): > _INFO_VERSION_CMD = "info version" > > # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA > controller > - _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000" > - _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"] > + # and the rest up to slot 11 will be used by QEMU implicitly. > + # Ganeti will add disks and NICs from slot 12 onwards. > + # NOTE: This maps to the default PCI bus created by pc machine type > + # by default (pci.0). The q35 creates a PCIe bus that is not > hotpluggable > + # and should be handled differently (pcie.0). > + _DEFAULT_PCI_RESERVATIONS = "11111111111100000000000000000000" > + # The SCSI bus is created on demand or automatically and is empty. > + # For simplicity we decide to use a different target (scsi-id) > + # for each SCSI disk. Here we support 16 SCSI disks which is > + # actually the current hard limit (constants.MAX_DISKS). > + # NOTE: Max device counts depend on the SCSI controller type; > + # Just for the record, lsi supports up to 7, megasas 64, > + # and virtio-scsi-pci 255. > + _DEFAULT_SCSI_RESERVATIONS = "0000000000000000" > > ANCILLARY_FILES = [ > _KVM_NETWORK_SCRIPT, > @@ -898,19 +1035,23 @@ class KVMHypervisor(hv_base.BaseHypervisor): > needs_boot_flag = self._BOOT_RE.search(kvmhelp) > > dev_opts = [] > - device_driver = None > disk_type = up_hvp[constants.HV_DISK_TYPE] > + # paravirtual implies either '-device virtio-blk-pci... -drive > if=none...' > + # for new QEMU versions or '-drive if=virtio' for old QEMU versions > if disk_type == constants.HT_DISK_PARAVIRTUAL: > - if_val = ",if=%s" % self._VIRTIO > - try: > - if self._VIRTIO_BLK_RE.search(devlist): > - if_val = ",if=none" > - # will be passed in -device option as driver > - device_driver = self._VIRTIO_BLK_PCI > - except errors.HypervisorError, _: > - pass > + driver = self._VIRTIO_BLK_PCI > + iface = self._VIRTIO > + else: > + driver = iface = disk_type > + > + # Check if a specific driver is supported by QEMU device model. > + if self._DEVICE_DRIVER_SUPPORTED(driver, devlist): > + if_val = ",if=none" # for the -drive option > + device_driver = driver # for the -device option > else: > - if_val = ",if=%s" % disk_type > + if_val = ",if=%s" % iface # for the -drive option > + device_driver = None # without -device option > + > # AIO mode > aio_mode = up_hvp[constants.HV_KVM_DISK_AIO] > if aio_mode == constants.HT_KVM_AIO_NATIVE: > @@ -947,16 +1088,16 @@ class KVMHypervisor(hv_base.BaseHypervisor): > drive_val = "file=%s,format=raw%s%s%s%s" % \ > (drive_uri, if_val, boot_val, cache_val, aio_val) > > - if device_driver: > - # 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) > - drive_val += (",id=%s" % kvm_devid) > - drive_val += (",bus=0,unit=%d" % cfdev.pci) > - dev_val = ("%s,drive=%s,id=%s" % > - (device_driver, kvm_devid, kvm_devid)) > - dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci) > + # virtio-blk-pci case > + if device_driver is not None: > + # hvinfo will exist for paravirtual devices either due to > + # _UpgradeSerializedRuntime() for old instances or due to > + # _GenerateKVMRuntime() for new instances. > + kvm_devid = cfdev.hvinfo["id"] > + drive_val += ",id=%s" % kvm_devid > + # Add driver, id, bus, and addr or channel, scsi-id, lun if any. > + dev_val = _GenerateDeviceHVInfoStr(cfdev.hvinfo) > + dev_val += ",drive=%s" % kvm_devid > dev_opts.extend(["-device", dev_val]) > > dev_opts.extend(["-drive", drive_val]) > @@ -1062,26 +1203,20 @@ class KVMHypervisor(hv_base.BaseHypervisor): > > kvm_cmd.extend(["-pidfile", pidfile]) > > - pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS) > + bus_slots = self._GetBusSlots() > > # As requested by music lovers > if hvp[constants.HV_SOUNDHW]: > soundhw = hvp[constants.HV_SOUNDHW] > - # For some reason only few sound devices require a PCI slot > - # while the Audio controller *must* be in slot 3. > - # That's why we bridge this option early in command line > - if soundhw in self._SOUNDHW_WITH_PCI_SLOT: > - _ = utils.GetFreeSlot(pci_reservations, reserve=True) > kvm_cmd.extend(["-soundhw", soundhw]) > > if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI: > - # The SCSI controller requires another PCI slot. > - _ = utils.GetFreeSlot(pci_reservations, reserve=True) > + # In case a SCSI disk is given, QEMU adds > + # a SCSI contorller (LSI Logic / Symbios Logic 53c895a) > + # implicitly. > + pass > > - # Add id to ballon and place to the first available slot (3 or 4) > - addr = utils.GetFreeSlot(pci_reservations, reserve=True) > - pci_info = ",bus=pci.0,addr=%s" % hex(addr) > - kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info]) > + kvm_cmd.extend(["-balloon", "virtio"]) > kvm_cmd.extend(["-daemonize"]) > if not instance.hvparams[constants.HV_ACPI]: > kvm_cmd.extend(["-no-acpi"]) > @@ -1317,9 +1452,7 @@ class KVMHypervisor(hv_base.BaseHypervisor): > else: > # Enable the spice agent communication channel between the host > and the > # agent. > - addr = utils.GetFreeSlot(pci_reservations, reserve=True) > - pci_info = ",bus=pci.0,addr=%s" % hex(addr) > - kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % > pci_info]) > + kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice"]) > kvm_cmd.extend([ > "-device", > "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0", > @@ -1366,14 +1499,21 @@ class KVMHypervisor(hv_base.BaseHypervisor): > if hvp[constants.HV_KVM_EXTRA]: > kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" ")) > > + def _generate_kvm_device(dev_type, dev): > + """Helper for generating a kvm device out of a Ganeti device.""" > + kvm_devid = _GenerateDeviceKVMId(dev_type, dev) > + hv_dev_type = _DEVICE_TYPE[dev_type](hvp) > + dev.hvinfo = _GenerateDeviceHVInfo(dev_type, kvm_devid, > + hv_dev_type, bus_slots) > + > kvm_disks = [] > for disk, link_name, uri in block_devices: > - disk.pci = utils.GetFreeSlot(pci_reservations, disk.pci, True) > + _generate_kvm_device(constants.HOTPLUG_TARGET_DISK, disk) > kvm_disks.append((disk, link_name, uri)) > > kvm_nics = [] > for nic in instance.nics: > - nic.pci = utils.GetFreeSlot(pci_reservations, nic.pci, True) > + _generate_kvm_device(constants.HOTPLUG_TARGET_NIC, nic) > kvm_nics.append(nic) > > hvparams = hvp > @@ -1496,15 +1636,13 @@ class KVMHypervisor(hv_base.BaseHypervisor): > } > update_features = {} > if nic_type == constants.HT_NIC_PARAVIRTUAL: > - nic_model = self._VIRTIO > - try: > - if self._VIRTIO_NET_RE.search(devlist): > - nic_model = self._VIRTIO_NET_PCI > - update_features["vnet_hdr"] = up_hvp[constants.HV_VNET_HDR] > - except errors.HypervisorError, _: > + if self._DEVICE_DRIVER_SUPPORTED(self._VIRTIO_NET_PCI, devlist): > + nic_model = self._VIRTIO_NET_PCI > + update_features["vnet_hdr"] = up_hvp[constants.HV_VNET_HDR] > + else: > # Older versions of kvm don't support DEVICE_LIST, but they don't > # have new virtio syntax either. > - pass > + nic_model = self._VIRTIO > > if up_hvp[constants.HV_VHOST_NET]: > # Check for vhost_net support. > @@ -1620,16 +1758,14 @@ class KVMHypervisor(hv_base.BaseHypervisor): > vhostfd = "" > > if kvm_supports_netdev: > - nic_val = "%s,mac=%s" % (nic_model, nic.mac) > - try: > - # kvm_nics already exist in old runtime files and thus there > might > - # be some entries without pci slot (therefore try: except:) > - kvm_devid = > _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic) > - netdev = kvm_devid > - nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, > hex(nic.pci))) > - except errors.HotplugError: > + # Non paravirtual NICs hvinfo is empty > + if "id" in nic.hvinfo: > + nic_val = _GenerateDeviceHVInfoStr(nic.hvinfo) > + netdev = nic.hvinfo["id"] > + else: > + nic_val = "%s" % nic_model > netdev = "netdev%d" % nic_seq > - nic_val += (",netdev=%s%s" % (netdev, nic_extra)) > + nic_val += (",netdev=%s,mac=%s%s" % (netdev, nic.mac, > nic_extra)) > tap_val = ("type=tap,id=%s,%s%s%s" % > (netdev, tapfd, vhostfd, tap_extra)) > kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val]) > @@ -1861,6 +1997,49 @@ class KVMHypervisor(hv_base.BaseHypervisor): > if (int(v_major), int(v_min)) < (1, 7): > raise errors.HotplugError("Hotplug not supported for qemu versions > < 1.7") > > + def _GetBusSlots(self, runtime=None): > + """Helper function to get the slots of PCI and SCSI QEMU buses. > + > + This will return the status of the first PCI and SCSI buses. By > default > + QEMU boots with one PCI bus (pci.0) and occupies the first 3 PCI > slots. If > + a SCSI disk is found then a SCSI controller is added on the PCI bus > and a > + SCSI bus (scsi.0) is created. > + > + During hotplug we could query QEMU via info qtree HMP command but > parsing > + the result is too complicated. Instead we use the info stored in > runtime > + files. We parse NIC and disk entries and based on their hvinfo we > reserve > + the corresponding slots. > + > + The runtime argument is a tuple as returned by _LoadKVMRuntime(). > Obtain > + disks and NICs from it. In case a runtime file is not available (see > + _GenerateKVMRuntime()) we return the bus slots that QEMU boots with by > + default. > + > + """ > + # This is by default and returned during _GenerateKVMRuntime() > + bus_slots = { > + _PCI_BUS: bitarray(self._DEFAULT_PCI_RESERVATIONS), > + _SCSI_BUS: bitarray(self._DEFAULT_SCSI_RESERVATIONS), > + } > + > + # This is during hot-add > + if runtime: > + _, nics, _, disks = runtime > + disks = [d for d, _, _ in disks] > + for d in disks + nics: > + if not d.hvinfo or "bus" not in d.hvinfo: > + continue > + bus = d.hvinfo["bus"] > + slots = bus_slots[bus] > + if bus == _PCI_BUS: > + slot = d.hvinfo["addr"] > + slots[int(slot, 16)] = True > + elif bus == _SCSI_BUS: > + slot = d.hvinfo["scsi-id"] > + slots[slot] = True > + > + return bus_slots > + > @_with_qmp > def _VerifyHotplugCommand(self, _instance, > device, kvm_devid, should_exist): > diff --git a/lib/objects.py b/lib/objects.py > index 0ce3c0f..8b5a926 100644 > --- a/lib/objects.py > +++ b/lib/objects.py > @@ -522,7 +522,7 @@ class ConfigData(ConfigObject): > class NIC(ConfigObject): > """Config object representing a network card.""" > __slots__ = ["name", "mac", "ip", "network", > - "nicparams", "netinfo", "pci"] + _UUID > + "nicparams", "netinfo", "pci", "hvinfo"] + _UUID > > @classmethod > def CheckParameterSyntax(cls, nicparams): > @@ -564,6 +564,7 @@ class Disk(ConfigObject): > "params", > "spindles", > "pci", > + "hvinfo", > "serial_no", > # dynamic_params is special. It depends on the node this instance > # is sent to, and should not be persisted. > diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs > index da5233f..7b8ece5 100644 > --- a/src/Ganeti/Constants.hs > +++ b/src/Ganeti/Constants.hs > @@ -2727,6 +2727,25 @@ htDiskScsi = "scsi" > htDiskSd :: String > htDiskSd = "sd" > > +htDiskScsiGeneric :: String > +htDiskScsiGeneric = "scsi-generic" > + > +htDiskScsiBlock :: String > +htDiskScsiBlock = "scsi-block" > + > +htDiskScsiCd :: String > +htDiskScsiCd = "scsi-cd" > + > +htDiskScsiHd :: String > +htDiskScsiHd = "scsi-hd" > + > +htScsiDeviceTypes :: FrozenSet String > +htScsiDeviceTypes = > + ConstantUtils.mkSet [htDiskScsiGeneric, > + htDiskScsiBlock, > + htDiskScsiCd, > + htDiskScsiHd] > + > htHvmValidDiskTypes :: FrozenSet String > htHvmValidDiskTypes = ConstantUtils.mkSet [htDiskIoemu, htDiskParavirtual] > > @@ -2737,7 +2756,11 @@ htKvmValidDiskTypes = > htDiskParavirtual, > htDiskPflash, > htDiskScsi, > - htDiskSd] > + htDiskSd, > + htDiskScsiGeneric, > + htDiskScsiBlock, > + htDiskScsiHd, > + htDiskScsiCd] > > htCacheDefault :: String > htCacheDefault = "default" > diff --git a/src/Ganeti/Types.hs b/src/Ganeti/Types.hs > index 52c30f1..f311827 100644 > --- a/src/Ganeti/Types.hs > +++ b/src/Ganeti/Types.hs > @@ -947,8 +947,8 @@ $(THH.makeJSONInstance ''HotplugAction) > -- | Hotplug Device Target. > > $(THH.declareLADT ''String "HotplugTarget" > - [ ("HTDisk", "hotdisk") > - , ("HTNic", "hotnic") > + [ ("HTDisk", "disk") > + , ("HTNic", "nic") > ]) > $(THH.makeJSONInstance ''HotplugTarget) > > diff --git a/test/data/kvm_runtime.json b/test/data/kvm_runtime.json > index d9fb8c1..099ce60 100644 > --- a/test/data/kvm_runtime.json > +++ b/test/data/kvm_runtime.json > @@ -31,7 +31,12 @@ > "link": "br0", > "mode": "bridged" > }, > - "pci": 6, > + "hvinfo": { > + "driver": "virtio-net-pci", > + "id": "nic-003fc157-66a8-4e6d", > + "bus": "pci.0", > + "addr": "0x8" > + }, > "uuid": "003fc157-66a8-4e6d-8b7e-ec4f69751396" > } > ], > @@ -108,7 +113,12 @@ > "params": { > "stripes": 1 > }, > - "pci": 4, > + "hvinfo": { > + "driver": "virtio-blk-pci", > + "id": "disk-7c079136-2573-4112", > + "bus": "pci.0", > + "addr": "0x9" > + }, > "size": 1024, > "uuid": "7c079136-2573-4112-82d0-0d3d2aa90d8f" > }, > @@ -128,7 +138,12 @@ > "params": { > "stripes": 1 > }, > - "pci": 5, > + "hvinfo": { > + "driver": "virtio-blk-pci", > + "id": "disk-9f5c5bd4-6f60-480b", > + "bus": "pci.0", > + "addr": "0xa" > + }, > "size": 512, > "uuid": "9f5c5bd4-6f60-480b-acdc-9bb1a4b7df79" > }, > diff --git a/test/py/ganeti.hypervisor.hv_kvm_unittest.py b/test/py/ > ganeti.hypervisor.hv_kvm_unittest.py > index 4f0fbf6..5ea7ebb 100755 > --- a/test/py/ganeti.hypervisor.hv_kvm_unittest.py > +++ b/test/py/ganeti.hypervisor.hv_kvm_unittest.py > @@ -462,11 +462,52 @@ class TestGenerateDeviceKVMId(unittest.TestCase): > device = objects.NIC() > target = constants.HOTPLUG_TARGET_NIC > fn = hv_kvm._GenerateDeviceKVMId > - self.assertRaises(errors.HotplugError, fn, target, device) > - > - device.pci = 5 > device.uuid = "003fc157-66a8-4e6d-8b7e-ec4f69751396" > - self.assertTrue(re.match("hotnic-003fc157-pci-5", fn(target, device))) > + self.assertTrue(re.match("nic-003fc157-66a8-4e6d", fn(target, > device))) > + > + > +class TestGenerateDeviceHVInfo(testutils.GanetiTestCase): > + def testPCI(self): > + self.MockOut(mock.patch('ganeti.utils.EnsureDirs')) > + hypervisor = hv_kvm.KVMHypervisor() > + dev_type = constants.HOTPLUG_TARGET_NIC > + kvm_devid = "nic-9e7c85f6-b6e5-4243" > + hv_dev_type = constants.HT_NIC_PARAVIRTUAL > + bus_slots = hypervisor._GetBusSlots() > + hvinfo = hv_kvm._GenerateDeviceHVInfo(dev_type, > + kvm_devid, > + hv_dev_type, > + bus_slots) > + expected_hvinfo = { > + "driver": "virtio-net-pci", > + "id": kvm_devid, > + "bus": "pci.0", > + "addr": hex(16), > + } > + > + self.assertTrue(hvinfo == expected_hvinfo) > + > + def testSCSI(self): > + self.MockOut(mock.patch('ganeti.utils.EnsureDirs')) > + hypervisor = hv_kvm.KVMHypervisor() > + dev_type = constants.HOTPLUG_TARGET_DISK > + kvm_devid = "disk-932df160-7a22-4067" > + hv_dev_type = constants.HT_DISK_SCSI_BLOCK > + bus_slots = hypervisor._GetBusSlots() > + hvinfo = hv_kvm._GenerateDeviceHVInfo(dev_type, > + kvm_devid, > + hv_dev_type, > + bus_slots) > + expected_hvinfo = { > + "driver": "scsi-block", > + "id": kvm_devid, > + "bus": "scsi.0", > + "channel": 0, > + "scsi-id": 0, > + "lun": 0, > + } > + > + self.assertTrue(hvinfo == expected_hvinfo) > > > class TestGetRuntimeInfo(unittest.TestCase): > @@ -490,7 +531,7 @@ class TestGetRuntimeInfo(unittest.TestCase): > > device.uuid = "003fc157-66a8-4e6d-8b7e-ec4f69751396" > devinfo = hv_kvm._GetExistingDeviceInfo(target, device, runtime) > - self.assertTrue(devinfo.pci==6) > + self.assertTrue(devinfo.hvinfo["addr"] == "0x8") > > def testDisk(self): > device = objects.Disk() > @@ -501,7 +542,7 @@ class TestGetRuntimeInfo(unittest.TestCase): > > device.uuid = "9f5c5bd4-6f60-480b-acdc-9bb1a4b7df79" > (devinfo, _, __) = hv_kvm._GetExistingDeviceInfo(target, device, > runtime) > - self.assertTrue(devinfo.pci==5) > + self.assertTrue(devinfo.hvinfo["addr"] == "0xa") > > > class PostfixMatcher(object): > -- > 1.7.10.4 > > Hrvoje Ribicic Ganeti Engineering Google Germany GmbH Dienerstr. 12, 80331, München Geschäftsführer: Matthew Scott Sucherman, Paul Terence Manicle Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Diese E-Mail ist vertraulich. Wenn Sie nicht der richtige Adressat sind, leiten Sie diese bitte nicht weiter, informieren Sie den Absender und löschen Sie die E-Mail und alle Anhänge. Vielen Dank. This e-mail is confidential. If you are not the right addressee please do not forward it, please inform the sender, and please erase this e-mail including any attachments. Thanks.
