diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py index c4ccb4107c4..c717bf66567 100644 --- a/nova/conf/libvirt.py +++ b/nova/conf/libvirt.py @@ -104,7 +104,7 @@ """), cfg.StrOpt('virt_type', default='kvm', - choices=('kvm', 'lxc', 'qemu', 'parallels'), + choices=('kvm', 'lxc', 'qemu', 'parallels', 'ch'), help=""" Describes the virtualization type (or so called domain type) libvirt should use. diff --git a/nova/privsep/libvirt.py b/nova/privsep/libvirt.py index 6ca99b98b42..5661ee25ccc 100644 --- a/nova/privsep/libvirt.py +++ b/nova/privsep/libvirt.py @@ -18,6 +18,7 @@ """ import binascii +import fcntl import os import stat @@ -156,15 +157,24 @@ def readpty(path): # exception here... Some platforms (I'm looking at you Windows) # don't have a fcntl and we may as well let them know that # with an ImportError, not that they should be calling this at all. - import fcntl + import select try: + epoll = select.epoll() with open(path, 'r') as f: - current_flags = fcntl.fcntl(f.fileno(), fcntl.F_GETFL) - fcntl.fcntl(f.fileno(), fcntl.F_SETFL, - current_flags | os.O_NONBLOCK) - - return f.read() + # this is not accepted by the unit test + # os.set_blocking(f.fileno(), False) + # therefore we use fnctl directly + flags = fcntl.fcntl(f.fileno(), fcntl.F_GETFL) + fcntl.fcntl(f.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK) + epoll.register(f.fileno(), select.EPOLLIN) + poll_list = epoll.poll(1) + data = '' + for _ in poll_list: + data += f.read() + epoll.unregister(f.fileno()) + epoll.close() + return data except Exception as exc: # NOTE(mikal): dear internet, I see you looking at me with your diff --git a/nova/tests/unit/privsep/test_libvirt.py b/nova/tests/unit/privsep/test_libvirt.py index eebcf6c2313..9c679577512 100644 --- a/nova/tests/unit/privsep/test_libvirt.py +++ b/nova/tests/unit/privsep/test_libvirt.py @@ -20,6 +20,7 @@ import ddt import os +import logging import nova.privsep.libvirt from nova import test from nova.tests import fixtures @@ -146,6 +147,8 @@ def fake_import(module, *args): [mock.call(mock_fileno, mock_fcntl.F_GETFL), mock.call(mock_fileno, mock_fcntl.F_SETFL, 32769 | os.O_NONBLOCK)]) + # Print all calls recorded by mock_open + logging.getLogger().info("mock_open.mock_calls: %s", mock_open.mock_calls) self.assertIn(mock.call('/fake/path', 'r'), mock_open.mock_calls) def test_create_nmdev(self): diff --git a/nova/virt/libvirt/blockinfo.py b/nova/virt/libvirt/blockinfo.py index 4efc6fbaeb1..124aa1b7e5c 100644 --- a/nova/virt/libvirt/blockinfo.py +++ b/nova/virt/libvirt/blockinfo.py @@ -95,6 +95,7 @@ 'qemu': ['virtio', 'scsi', 'ide', 'usb', 'fdc', 'sata'], 'kvm': ['virtio', 'scsi', 'ide', 'usb', 'fdc', 'sata'], 'lxc': ['lxc'], + 'ch': ['virtio'], 'parallels': ['ide', 'scsi'], # we no longer support UML or Xen, but we keep track of their bus types so # we can reject them for other virt types @@ -276,6 +277,8 @@ def get_disk_bus_for_device_type(instance, return "ide" elif device_type == "disk": return "scsi" + elif virt_type == "ch": + return "virtio" else: # If virt-type not in list then it is unsupported raise exception.UnsupportedVirtType(virt=virt_type) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 71dca0410ac..99de5bea8bd 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -1379,6 +1379,8 @@ def _uri(): uri = CONF.libvirt.connection_uri or 'lxc:///' elif CONF.libvirt.virt_type == 'parallels': uri = CONF.libvirt.connection_uri or 'parallels:///system' + elif CONF.libvirt.virt_type == 'ch': + uri = CONF.libvirt.connection_uri or 'ch:///session' else: uri = CONF.libvirt.connection_uri or 'qemu:///system' return uri @@ -4494,7 +4496,8 @@ def get_console_output(self, context, instance): path_sources = [ ('file', "./devices/console[@type='file']/source[@path]", 'path'), ('tcp', "./devices/console[@type='tcp']/log[@file]", 'file'), - ('pty', "./devices/console[@type='pty']/source[@path]", 'path')] + ('pty', "./devices/console[@type='pty']/source[@path]", 'path'), + ('pty', "./devices/serial[@type='pty']/source[@path]", 'path'), ] console_type = "" console_path = "" for c_type, epath, attrib in path_sources: @@ -6735,6 +6738,9 @@ def _configure_guest_by_virt_type( guest.os_init_path = "/sbin/init" guest.os_cmdline = CONSOLE guest.os_init_env["product_name"] = "OpenStack Nova" + elif CONF.libvirt.virt_type == "ch": + guest.virt_type = 'kvm' + guest.os_kernel = "/usr/share/cloud-hypervisor/CLOUDHV_EFI.fd" elif CONF.libvirt.virt_type == "parallels": if guest.os_type == fields.VMMode.EXE: guest.os_init_path = "/sbin/init" @@ -6780,6 +6786,11 @@ def _create_consoles(self, guest_cfg, instance, flavor, image_meta): self._create_pty_device( guest_cfg, vconfig.LibvirtConfigGuestConsole, log_path=log_path) + elif CONF.libvirt.virt_type == "ch": + consolepty = vconfig.LibvirtConfigGuestSerial() + consolepty.type = "pty" + guest_cfg.add_device(consolepty) + else: # qemu, kvm if self._is_s390x_guest(image_meta): self._create_consoles_s390x( @@ -6969,6 +6980,8 @@ def _guest_add_usb_root_controller(self, guest, image_meta): here explicitly so that we can _disable_ it (by setting the model to 'none') if it's not necessary. """ + if CONF.libvirt.virt_type == "ch": + return usbhost = vconfig.LibvirtConfigGuestUSBHostController() usbhost.index = 0 # an unset model means autodetect, while 'none' means don't add a @@ -7378,6 +7391,8 @@ def _guest_add_accel_pci_devices(self, guest, accel_info): def _guest_add_video_device(guest): if CONF.libvirt.virt_type == 'lxc': return False + elif CONF.libvirt.virt_type == "ch": + return False # NB some versions of libvirt support both SPICE and VNC # at the same time. We're not trying to second guess which diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py index f67ccf9bbf7..2ae47c2a702 100644 --- a/nova/virt/libvirt/host.py +++ b/nova/virt/libvirt/host.py @@ -1241,6 +1241,7 @@ def write_instance_config(self, xml): :returns: an instance of Guest """ + LOG.info(xml) domain = self.get_connection().defineXML(xml) return libvirt_guest.Guest(domain) diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 6e9069fa50f..30456e678d2 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -78,6 +78,9 @@ network_model.VIF_MODEL_RTL8139, network_model.VIF_MODEL_E1000, ], + 'ch': [ + network_model.VIF_MODEL_VIRTIO, + ], } @@ -172,7 +175,7 @@ def get_vif_model(self, image_meta=None, vif_model=None): # If the virt type is KVM/QEMU/VZ(Parallels), then use virtio according # to the global config parameter if (model is None and CONF.libvirt.virt_type in - ('kvm', 'qemu', 'parallels') and + ('kvm', 'qemu', 'parallels', 'ch') and CONF.libvirt.use_virtio_for_bridges): model = network_model.VIF_MODEL_VIRTIO